<?php
/**
 * Version 7.0.1
 * Date: 25 Jun 2026
 *
 * SiteGuarding.com Antivirus 
 */
include("antivirus_config.php");
 
define('SCRIPT_VERSION', '7.0.1');
define('ANTIVIRUS_PLATFORM', 'any');
define('ANTIVIRUS_CMS', 'any');

define('SITEGUARDING_SERVER', 'http://www.siteguarding.com/ext/antivirus/index.php');



//define('DEBUG_FLAG', true);
//define('DEBUG_FILELIST', false);
//define('CALLBACK_PACK_FILE', false);


// Init
date_default_timezone_set('Europe/London');
ignore_user_abort(true);
error_reporting( 0 );
ini_set('log_errors',0);
ini_set('max_execution_time',7200);
set_time_limit ( 7200 );
ini_set('post_max_size', '256M');
ini_set('upload_max_filesize', '256M');
ini_set('memory_limit', '512M');



// Self Debug
if (!function_exists('SiteGuardingAllErrorsDebug_0E6AC80FB9AA_antivirus'))
{
    function SiteGuardingAllErrorsDebug_0E6AC80FB9AA_antivirus($errno, $errstr, $errfile, $errline)
    {
        if ($errline == 123 || $errline == 127) return;
        
    		switch($errno) 
    		{ 
    			case E_ERROR:
                    $errno_txt = 'E_ERROR'; break;
                case E_CORE_ERROR:
                    $errno_txt =  'E_CORE_ERROR'; break;
                case E_COMPILE_ERROR:
                    $errno_txt =  'E_COMPILE_ERROR'; break;
                case E_USER_ERROR:
                    $errno_txt =  'E_USER_ERROR'; break;
                case E_RECOVERABLE_ERROR:
                    $errno_txt =  'E_RECOVERABLE_ERROR'; break;
                    
				default:
					$errno_txt = '';
    		}
            
            if ($errno_txt == '') return;
    	
        $log_file = dirname(__FILE__).'/antivirus.debug.log';
        
        $application = 'antivirus';
        $domain = $_SERVER['HTTP_HOST'];
        
        $line = array();
        $line['date'] = date("Y-m-d H:i:s");
        $line['ip'] = 'IP: '.$_SERVER['REMOTE_ADDR'];
        $line['type'] = 'Type: '.$errno_txt;
        $line['msg'] = 'Msg: '.$errstr;
        $line['file'] = 'File: '.$errfile;
        $line['line'] = 'Line: '.$errline;
        $line['url'] = 'URL: '.$_SERVER['REQUEST_URI'];
    
        // Save to file
    	$fp = fopen($log_file, 'a');
    	fwrite($fp, implode(", ", $line)."\n");
    	fclose($fp);
        
        // Inform SiteGuarding
    	$post = array(
    		'action' => 'inform',
    		'domain' => $domain,
    		'application' => $application,
    		'file' => $errfile,
    		'text' => implode(", ", $line),
    		'md5'   => 'none',
    	);
        if ($errfile != '' && is_file($errfile)) $post['md5'] = md5_file($errfile);

        
        $link = 'https://www.siteguarding.com/ext/devalerts/index.php';
        $client = EasyRequest_AVP::create('POST', $link, array(
            'form_params' => $post
        ));
        $client->send();
        $pageContents = trim($client->getResponseBody());
    }
}
$old_error_handler_0E6AC80FB9AA = set_error_handler("SiteGuardingAllErrorsDebug_0E6AC80FB9AA_antivirus");



/**
 * EasyRequest
 */
class EasyRequest_AVP { const BOUNDARY_PLACEHOLDER = '##BOUNDARY##'; protected $options = array( 'handler' => null, 'method' => 'GET', 'url' => '', 'nobody' => false, 'follow_redirects' => 1, 'protocol_version' => '1.1', 'timeout' => 30, 'user_agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:38.0) Gecko/20100101 Firefox/38.0', 'auth' => null, 'proxy' => null, 'proxy_userpwd' => null, 'proxy_type' => 'http', 'headers' => array(), 'cookies' => array(), 'json' => false, 'body' => '', 'query' => array(), 'form_params' => array(), 'multipart' => array(), 'curl' => array(), ); public $request; public $response; protected $redirects = array( 'count' => 0, 'urls' => array(), 'cookies' => array(), 'requests' => array(), ); protected $debugInfo = array( 'time_start' => null, 'time_process' => null, 'handler' => null, 'errors' => array(), ); private $builder = array( 'headers' => array(), 'query' => array(), 'form_params' => array(), ); private function __construct() { } public function setOptions($key, $value = null) { if (is_array($key)) { foreach ($key as $k => $v) { $this->setOptions($k, $v); } } elseif (!array_key_exists($key, $this->options)) { throw new InvalidArgumentException(sprintf('Option "%s" is invalid.', $key)); } else { $this->options[$key] = $value; } return $this; } public function getOptions($key = null) { if ($key === null) { return $this->options; } elseif (!array_key_exists($key, $this->options)) { throw new InvalidArgumentException(sprintf('Option "%s" is invalid.', $key)); } return $this->options[$key]; } public static function create($url, $method = 'GET', $options = array()) { if (strpos($method, '://')) { $temp = $url; $url = $method; $method = $temp; } $object = new self; $params = array( 'form_params' => 'withFormParam', 'query' => 'withQuery' ); foreach ($params as $key => $setter) { if (isset($options[$key])) { $object->$setter($object->getParamsAsString($options[$key])); unset($options[$key]); } } if (!empty($options['headers'])) { foreach ($options['headers'] as $name => $values) { if (is_int($name)) { list($name, $value) = explode(':', $values, 2); $object->withHeader($name, $value); } else { $object->withHeader($name, $values); } } } if (!empty($options['cookies']) && is_string($options['cookies'])) { $object->withStringCookies($options['cookies']); unset($options['cookies']); } return $object->setOptions(array('method' => strtoupper($method), 'url' => $url) + $options); } public static function __callStatic($method, $arguments) { static $methods = array( 'OPTIONS' => 1, 'GET' => 1, 'HEAD' => 1, 'POST' => 1, 'PUT' => 1, 'DELETE' => 1, 'TRACE' => 1, 'CONNECT' => 1 ); if (!empty($methods[strtoupper($method)])) { return self::create($method, $arguments[0], isset($arguments[1]) ? $arguments[1] : array())->send(); } throw new Exception(sprintf('Method "%s" is not defined.', $method)); } public function send() { list($options, $request) = $this->prepareRequest(); if (empty($request['uri'])) { throw new Exception('Request URI cannot be empty.'); } $this->options = $options; $this->request = $request; $this->response = null; $handler = $this->getHandler(); $sendMethod = sprintf('sendWith%s', ucfirst($handler)); $this->debugInfo['handler'] = $handler; $this->debugInfo['time_start'] = microtime(true); $info = $this->$sendMethod($this->request); $this->debugInfo['time_process'] = microtime(true) - $this->debugInfo['time_start']; if ($info !== false) { $this->response = array( 'header' => $info[0], 'body' => $info[1] ); $this->followRedirects(); } return $this; } protected function followRedirects() { $client = clone $this; while (($this->options['follow_redirects'] === true || $this->options['follow_redirects'] > $this->redirects['count']) && $nextUrl = $client->getResponseHeaderLine('Location') ) { $nextUrl = $this->getAbsoluteUrl($nextUrl, $client->options['url']); if ($this->redirects['count'] === 0) { $this->redirects['urls'][] = $client->options['url']; $this->redirects['requests'][] = $client; $this->redirects['cookies'] = array_values($client->options['cookies']); $this->collectResponseCookies($this->redirects['cookies'], $client->getResponseArrayCookies()); } $reuseOptions = array( 'nobody', 'protocol_version', 'timeout', 'user_agent', 'auth', 'headers', 'proxy', 'proxy_userpwd', 'proxy_type', 'query' ); $options = array('cookies' => $this->redirects['cookies']); foreach ($reuseOptions as $key) { $options[$key] = $this->options[$key]; } $client = self::create('GET', $nextUrl, $options)->send(); $this->request = $client->request; $this->response = $client->response; $this->redirects['count']++; $this->redirects['urls'][] = $client->options['url']; $this->redirects['requests'][] = $client; $this->collectResponseCookies($this->redirects['cookies'], $client->getResponseArrayCookies()); } } private function collectResponseCookies(&$collection, $cookies) { if (!$cookies) { return; } foreach ($collection as $oldKey => $oldValue) { foreach ($cookies as $newKey => $newValue) { if ($oldValue['Name'] === $newValue['Name'] && $oldValue['Path'] === $newValue['Path'] && $oldValue['Domain'] === $newValue['Domain'] && $oldValue['Secure'] === $newValue['Secure'] && $oldValue['HttpOnly'] === $newValue['HttpOnly'] ) { $collection[$oldKey] = $newValue; unset($cookies[$newKey]); } } } $collection = array_merge($collection, $cookies); } public function getCurrentUrl() { return $this->getRedirectedCount() ? end($this->redirects['urls']) : $this->options['url']; } public function getAllResponseCookies() { return $this->getRedirectedCount() ? $this->getRedirectedCookies() : $this->getResponseArrayCookies(); } public function getRedirectedCount() { return $this->redirects['count']; } public function getRedirectedUrls() { return $this->redirects['urls']; } public function getRedirectedCookies() { return $this->redirects['cookies']; } public function getRedirectedRequests() { return $this->redirects['requests']; } public function getDebugInfo($key = null) { if ($key !== null) { return $this->debugInfo[$key]; } return $this->debugInfo; } public function getRequest($key = null) { if ($key !== null) { return $this->request[$key]; } return $this->request; } public function getResponse($key = null) { if ($key !== null) { return $this->response[$key]; } return $this->response; } public function __toString() { return !$this->response ? '' : $this->getResponseBody(); } public function getResponseBody() { return !$this->response ? false : $this->response['body']; } public function getResponseHeaders() { return !$this->response ? false : $this->getHeadersAsLines($this->response['header']['headers']); } public function getResponseHeader($name) { return !$this->response ? false : $this->getHeaderAsLines($this->response['header']['headers'], $name); } public function getResponseHeaderLine($line) { return !$this->response ? false : $this->getHeaderLine($this->response['header']['headers'], $line); } public function getResponseArrayCookies() { if (!$this->response) { return false; } $cookies = array(); $cookieLines = $this->getHeaderAsLines($this->response['header']['headers'], 'Set-Cookie'); foreach ($cookieLines as $cookie) { $cookies[] = $this->parseStringCookie($cookie); } return $cookies; } public function getResponseCookies() { if (!$this->response) { return false; } $cookies = ''; $cookieLines = $this->getHeaderAsLines($this->response['header']['headers'], 'Set-Cookie'); foreach ($cookieLines as $cookie) { $cookies .= $this->getCookieAsString($this->parseStringCookie($cookie), false); } return trim($cookies); } public function getResponseStatus() { return !$this->response ? false : $this->response['header']['status']; } public function getResponseReason() { return !$this->response ? false : $this->response['header']['reason']; } public function getResponseProtocolVersion() { return !$this->response ? false : $this->response['header']['protocol_version']; } protected function sendWithSocket(array $request) { static $ports = array( 'https' => 443, 'http' => 80, '' => 80); static $errorHandler = null; $uri = $request['uriInfo']; $host = ($uri['scheme'] == 'https' ? 'ssl://' : '').$uri['host']; $port = $uri['port'] ? $uri['port'] : $ports[$uri['scheme']]; $path = $uri['path'].($uri['query'] ? '?'.$uri['query'] : ''); $headers = $request['headers']; if ($this->options['proxy']) { list($host, $port) = explode(':', $this->options['proxy']); $path = $request['uri']; if ($this->options['proxy_userpwd']) { $headers[] = 'Proxy-Authorization: Basic '.base64_encode($this->options['proxy_userpwd']); } } $headers[] = 'Connection: close'; $message = sprintf("%s %s HTTP/%s\r\n", $request['method'], $path, $request['protocol_version']); $message .= sprintf("Host: %s\r\n", $uri['host']); $message .= implode("\r\n", $headers)."\r\n"; $message .= "\r\n"; $message .= $request['body']; $message .= "\r\n\r\n"; $errorHandler === null && $errorHandler = function(){}; $handler = set_error_handler($errorHandler); $stream = fsockopen($host, $port, $errno, $errstr, $this->options['timeout']); $handler ? set_error_handler($handler) : restore_error_handler(); if (!$stream) { if ($errstr) { $this->debugInfo['errors'][] = sprintf('ERROR: %d - %s.', $errno, $errstr); } else { $this->debugInfo['errors'][] = sprintf('ERROR: Cannot connect to "%s:%s"', $host, $port); } return false; } fwrite($stream, $message); $headers = $body = ''; do { $headers .= fgets($stream, 128); } while (strpos($headers, "\r\n\r\n") === false); $headers = $this->parseResponseHeaders($headers); if (!$this->options['nobody']) { while (!feof($stream)) { $body .= fgets($stream); } fclose($stream); if ($this->getHeaderLine($headers['headers'], 'Transfer-Encoding') == 'chunked') { $len = strlen($body); $outData = ''; $pos = 0; while ($pos < $len) { $rawnum = substr($body, $pos, strpos(substr($body, $pos), "\r\n") + 2); $num = hexdec(trim($rawnum)); $pos += strlen($rawnum); $chunk = substr($body, $pos, $num); $outData .= $chunk; $pos += strlen($chunk); } $body = $outData; } } return array($headers, $body); } protected function sendWithCurl(array $request) { $curlOptions = array( CURLOPT_CUSTOMREQUEST => $request['method'], CURLOPT_URL => $request['uri'], CURLOPT_HEADER => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_ENCODING => 'gzip, deflate', CURLOPT_NOBODY => $this->options['nobody'], CURLOPT_TIMEOUT => $this->options['timeout'], CURLOPT_HTTPHEADER => $request['headers'], ); if ($request['protocol_version'] == '1.0') { $curlOptions[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0; } else { $curlOptions[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1; } if ($body = $request['body']) { $curlOptions[CURLOPT_POSTFIELDS] = $body; } if ($this->options['proxy']) { $curlOptions[CURLOPT_PROXY] = $this->options['proxy']; static $proxyTypeOptions = array( 'http' => CURLPROXY_HTTP, 'sock5' => CURLPROXY_SOCKS5 ); $curlOptions[CURLOPT_PROXYTYPE] = $proxyTypeOptions[$this->options['proxy_type']]; if ($this->options['proxy_userpwd']) { $curlOptions[CURLOPT_PROXYUSERPWD] = $this->options['proxy_userpwd']; } } $curlOptions += $this->options['curl']; $ch = curl_init(); curl_setopt_array($ch, $curlOptions); $response = curl_exec($ch); if ($response === false) { $this->debugInfo['errors'][] = sprintf('ERROR: %d - %s.', curl_errno($ch), curl_error($ch)); return false; } $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); curl_close($ch); $headers = (string) substr($response, 0, $headerSize); $body = (string) substr($response, $headerSize); $headers = $this->parseResponseHeaders($headers); return array($headers, $body); } protected function parseResponseHeaders($headers) { $lines = array_filter(explode("\r\n", $headers)); preg_match('#^HTTP/([\d\.]+)\s(\d+)\s(.*?)$#i', array_shift($lines), $match); $out = array( 'protocol_version' => $match[1], 'status' => (int) $match[2], 'reason' => $match[3], 'headers' => array(), ); $this->addHeaderToArray($out['headers'], $lines, null); return $out; } public function prepareRequest() { $clone = clone $this; $uri = $clone->parseUri($clone->options['url']); if ($clone->options['query']) { $uri['query'] = trim($uri['query'].'&'.$clone->getParamsAsString($clone->options['query']), '&'); } $request = array( 'protocol_version' => $clone->options['protocol_version'], 'method' => strtoupper($clone->options['method']), 'uri' => $clone->getUriAsString($uri), 'uriInfo' => $uri, ); $clone->options['url'] = $request['uri']; if ($clone->options['json']) { !$clone->hasHeader('Content-Type') && $clone->withHeader('Content-Type', 'application/json'); $clone->options['body'] = $clone->options['json']; } $body = $params = $boundary = ''; if ($clone->options['form_params']) { $params = $clone->getParamsAsString($clone->options['form_params']); } if ($clone->options['multipart']) { $boundary = uniqid(); !$clone->hasHeader('Content-Type') && $clone->withHeader('Content-Type', 'multipart/form-data; boundary='.$boundary); if (preg_match_all('#([^=&]+)=([^&]*)#i', $params, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { $clone->withMultipart(urldecode($match[1]), urldecode($match[2])); } } $body .= $clone->getMultipartAsString($boundary, $clone->options['multipart']); } elseif ($params) { !$clone->hasHeader('Content-Type') && $clone->withHeader('Content-Type', 'application/x-www-form-urlencoded'); $body .= $params; } if ($clone->options['body']) { $body .= $clone->getBodyAsString($clone->options['body']); } if ($body) { if ($request['method'] == 'GET' || $request['method'] == 'HEAD') { $request['method'] = 'POST'; } } $clone->options['auth'] && $clone->withHeader('Authorization', 'Basic '.base64_encode($clone->options['auth'])); $cookies = ''; if ($clone->hasHeader('Cookie')) { foreach ($clone->getHeaderAsLines($clone->builder['headers'], 'Cookie') as $value) { $clone->withStringCookies($value); } } foreach ($clone->options['cookies'] as $cookie) { if ($clone->isCookieMatchesDomain($cookie, $uri['host']) && $clone->isCookieMatchesPath($cookie, $uri['path']) ) { $cookies .= $clone->getCookieAsString($cookie, false); } } $cookies && $clone->withHeader('Cookie', trim($cookies), false); $body && $clone->withHeader('Content-Length', strlen($body), false); $clone->withHeader('User-Agent', $clone->options['user_agent'], false); !$clone->hasHeader('Expect') && $body && $clone->withHeader('Expect', ''); $headers = $clone->getHeadersAsLines($clone->builder['headers']); if ($boundary) { foreach ($headers as &$line) { $line = strtr($line, array(self::BOUNDARY_PLACEHOLDER => $boundary)); } $body = strtr($body, array(self::BOUNDARY_PLACEHOLDER => $boundary)); } $request += array( 'headers' => $headers, 'body' => $body ); return array($clone->options, $request); } public function withMethod($method) { return $this->setOptions('method', $method); } public function withUserAgent($userAgent) { return $this->setOptions('user_agent', $userAgent); } public function withAuth($auth) { if ($auth === null || preg_match('#[\w-_]+(?::[\w-_]+)?#', $auth)) { return $this->setOptions('auth', $auth); } throw new InvalidArgumentException('Auth must be one of: string with format "user:pass" or "null".'); } public function withProxy($proxy, $userPwd = null, $type = 'http') { if ($proxy === null || preg_match('#^\d+\.\d+\.\d+\.\d+:\d+$#', $proxy)) { return $this ->setOptions('proxy', $proxy) ->setOptions('proxy_userpwd', $userPwd) ->setOptions('proxy_type', $type); } throw new InvalidArgumentException('Proxy must be one of: string with format "ip:port" or "null".'); } public function withHttpProxy($proxy, $userPwd = null) { return $this->withProxy($proxy, $userPwd, 'http'); } public function withSock5Proxy($proxy, $userPwd = null) { return $this->withProxy($proxy, $userPwd, 'sock5'); } public function withBody($body) { $this->options['json'] = false; return $this->setOptions('body', $body); } public function withJson($json) { if (is_string($json)) { $json = json_decode($json, true); if ($json === null) { throw new InvalidArgumentException('Json value must be an array or json string.'); } } $this->options['body'] = $this->options['json'] = json_encode($json); return $this; } public function withNobody($nobody) { return $this->setOptions('nobody', (bool) $nobody); } public function withFollowRedirects($maxRedirect) { if ($maxRedirect === true || is_numeric($maxRedirect) && 0 <= $maxRedirect = intval($maxRedirect)) { return $this->setOptions('follow_redirects', $maxRedirect); } throw new InvalidArgumentException('Max redirect must be a digit number or "true".'); } public function withTimeout($timeout) { if (is_numeric($timeout) && 0 <= $timeout = intval($timeout)) { $this->setOptions('timeout', (int) $timeout); return $this; } throw new InvalidArgumentException('Timeout must be be a digit number.'); } public function withProtocolVersion($version) { static $validProtocolVersions = array( '1.0' => true, '1.1' => true, '2.0' => true, ); if (empty($validProtocolVersions[$version])) { throw new Exception('Protocol version given is invalid.'); } return $this->setOptions('protocol_version', $version); } public function withHeader($name, $values = null, $append = true) { $this->addHeaderToArray($this->builder['headers'], $name, $values, $append); return $this->setOptions('headers', $this->getHeadersAsLines($this->builder['headers'])); } public function withoutHeader($name) { $this->removeHeaderFromArray($this->builder['headers'], $name); return $this; } public function hasHeader($name) { return $this->headerHasKey($this->builder['headers'], $name); } public function withStringCookies($cookies, $path = '/', $secure = false, $httpOnly = false) { $append = array( 'Path' => $path, 'Secure' => $secure, 'HttpOnly' => $httpOnly ); foreach ($this->parseStringCookies($cookies) as $c) { $this->options['cookies'][$c['Name']] = $c + $append; } return $this; } public function withCookie($name, $value = null, $path = '/', $secure = false, $httpOnly = false) { $append = array( 'Path' => $path, 'Secure' => $secure, 'HttpOnly' => $httpOnly ); if (is_array($name)) { if ($this->isCookieData($name)) { $this->options['cookies'][$name] = $name + $append; } else { foreach ($name as $k => $v) { $this->withCookie($k, $v); } } } elseif (is_string($name) && $value === null) { $c = $this->parseStringCookie($name); $this->options['cookies'][$c['Name']] = $c; } elseif (is_array($value) && $this->isCookieData($value)) { $this->options['cookies'][$value['Name']] = $value + $append; } else { $this->options['cookies'][$name] = array('Name' => $name, 'Value' => $value) + $append; } return $this; } public function withoutCookie($name) { unset($this->options['cookies'][$name]); return $this; } public function withFormFile($name, $filePath, $filename = null, $headers = array()) { $headers = array('Content-Transfer-Encoding' => 'binary') + $headers; if ($type = $this->getFileType($filePath)) { $headers['Content-Type'] = $type; } return $this->withMultipart($name, fopen($filePath, 'r'), $filename ? $filename : basename($filePath), $headers); } public function withMultipart($name, $contents, $filename = null, $headers = array()) { $this->options['multipart'][$name] = array( 'name' => $name, 'contents' => $contents, 'filename' => $filename, 'headers' => $headers ); return $this; } public function withoutMultipart($name) { unset($this->options['multipart'][$name]); return $this; } public function withQuery($name, $value = null, $append = true) { $this->addParamToArray($this->builder['query'], $name, $value, $append); $options = $this->getParamsAsArray($this->builder['query']); return $this->setOptions('query', $options); } public function withoutQuery($name) { $this->removeParamFromArray($this->builder['query'], $name); $options = $this->getParamsAsArray($this->builder['query']); return $this->setOptions('query', $options); } public function withFormParam($name, $value = null, $append = true) { $this->addParamToArray($this->builder['form_params'], $name, $value, $append); $options = $this->getParamsAsArray($this->builder['form_params']); return $this->setOptions('form_params', $options); } public function withoutFormParam($name) { $this->removeParamFromArray($this->builder['form_params'], $name); $options = $this->getParamsAsArray($this->builder['form_params']); return $this->setOptions('form_params', $options); } protected function addParamToArray(&$builder, $name, $value = null, $append = true) { if ($value !== null) { if (!$append || !isset($builder[$name])) { $builder[$name] = array(); } $builder[$name] = array_merge($builder[$name], (array) $value); } else { if (is_array($name)) { foreach ($name as $key => $value) { if (!is_int($key)) { $this->addParamToArray($builder, $key, $value, $append); } else { $this->addParamToArray($builder, $value, null, $append); } } } elseif (is_string($name)) { $name = str_replace('+', '%2B', preg_replace_callback( '#&[a-z]+;#', function($match) { return rawurlencode($match[0]); }, $name)); $this->addParamToArray($builder, $this->parseStringParams($name), null, $append); } } } protected function removeParamFromArray(&$builder, $name) { unset($builder[$name]); } protected function addHeaderToArray(&$builder, $name, $values, $append = true) { if (is_array($name)) { foreach ($name as $key => $value) { if (is_int($key)) { list($key, $value) = array_map('trim', explode(':', $value, 2)); } $this->addHeaderToArray($builder, $key, $value, $append); } return; } $normalizedKey = $this->normalizeHeaderKey($name); if (!$append || !isset($builder[$normalizedKey])) { $builder[$normalizedKey] = array(); } foreach ((array) $values as $value) { if (!is_string($value) && !is_numeric($value)) { throw new InvalidArgumentException('Header value must be a string or array of string.'); } $builder[$normalizedKey][] = array( 'key' => $name, 'value' => trim($value) ); } } protected function removeHeaderFromArray(&$builder, $name) { unset($builder[$this->normalizeHeaderKey($name)]); } protected function headerHasKey($builder, $name) { return array_key_exists($this->normalizeHeaderKey($name), $builder); } protected function getHeadersAsLines(array $builder) { $out = array(); foreach ($builder as $values) { foreach ($values as $value) { $out[] = sprintf('%s: %s', $value['key'], $value['value']); } } return $out; } protected function getHeaderAsLines(array $builder, $name) { $normallizedKey = $this->normalizeHeaderKey($name); $out = array(); if (isset($builder[$normallizedKey])) { foreach ($builder[$normallizedKey] as $value) { $out[] = $value['value']; } } return $out; } protected function normalizeHeaderKey($key) { return strtr(strtolower($key), '_', '-'); } protected function getHeaderLine($builder, $name) { $normallizedKey = $this->normalizeHeaderKey($name); $out = ''; if (isset($builder[$normallizedKey])) { foreach ($builder[$normallizedKey] as $value) { $out .= ($out ? ',' : '').$value['value']; } } return $out; } protected function getParamsAsArray(array $dataBuilder) { $params = array(); foreach ($dataBuilder as $key => $param) { if (count($param) == 1) { $params[$key] = $param[0]; } else { $params[$key] = $param; } } return $params; } protected function getParamsAsString(array $params) { if (PHP_VERSION_ID >= 50400) { return http_build_query($params, null, '&', PHP_QUERY_RFC3986); } else { return preg_replace_callback('#([^=&]+)=([^&]*)#i', function($match) { return $match[1]=rawurlencode(urldecode($match[2])); }, http_build_query($params)); } } protected function parseStringParams($queryString, &$array = array()) { if (empty($queryString)) { return array(); } $array = array(); foreach (explode('&', $queryString) as $query) { list($key, $value) = explode('=', $query, 2) + array('', ''); $key = urldecode($key); if (preg_match_all('#\[([^\]]+)?\]#i', $key, $matches)) { $key = str_replace($matches[0], '', $key); if (!isset($array[$key])) { $array[$key] = array(); } $children = & $array[$key]; $deth = array(); foreach ($matches[1] as $sub) { $sub = $sub !== '' ? $sub : count($children); if (!array_key_exists($sub, $children)) { $children[$sub] = array(); } $children = & $children[$sub]; } $children = urldecode($value); } else { $array[$key] = urldecode($value); } } return $array; } protected function getCookieDefaults() { static $defauls = array( 'Name' => null, 'Value' => null, 'Domain' => null, 'Path' => '/', 'Max-Age' => null, 'Expires' => null, 'Secure' => false, 'Discard' => false, 'HttpOnly' => false ); return $defauls; } public function parseStringCookies($values) { $array = array(); if (preg_match_all('#(?:^|;)\s*([^=]+)=([^;]+)\s*?#', $values, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { list(, $name, $value) = $match; if ( !strcasecmp($name, 'Expires') && strtotime($value) || !strcasecmp($name, 'Path') && urldecode($value) == $value || preg_match('#Domain|Max-Age|Secure|Discard|HttpOnly#i', $value) ) { continue; } $array[] = array('Name' => $name, 'Value' => $value) + $this->getCookieDefaults(); } } return $array; } protected function parseStringCookie($value) { $data = $this->getCookieDefaults(); if (is_string($value) && preg_match_all('#([^=;\s]+)(?:=([^;]+))?;?\s*?#', $value, $matches)) { $data['Name'] = array_shift($matches[1]); $data['Value'] = array_shift($matches[2]); if ($matches[1] && $matches[2]) { foreach ($this->getCookieDefaults() as $key => $value) { foreach ($matches[1] as $index => $val) { if (!strcasecmp($key, $val)) { if (in_array($key, array('Secure', 'Discard', 'HttpOnly'))) { $data[$key] = true; } else { $data[$key] = $matches[2][$index]; } } } } } } return $data; } protected function isCookieData(array $data) { return !empty($data['Name']) && isset($data['Value']); } protected function isCookieMatchesPath(array $cookie, $path) { return empty($cookie['Path']) || strpos($path, $cookie['Path']) === 0; } protected function isCookieMatchesDomain(array $cookie, $domain) { $cookieDomain = isset($cookie['Domain']) ? ltrim($cookie['Domain'], '.') : null; if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) { return true; } if (filter_var($domain, FILTER_VALIDATE_IP)) { return false; } return (bool) preg_match('/\.'.preg_quote($cookieDomain).'$/i', $domain); } protected function getCookieAsString(array $cookie, $fully = false) { $str = $cookie['Name'].'='.$cookie['Value'].'; '; if (!$fully) { return $str; } $cookie += $this->getCookieDefaults(); foreach ($cookie as $key => $value) { if ($key != 'Name' && $key != 'Value' && $value !== null && $value !== false) { if ($key == 'Expires') { $str .= 'Expires='.gmdate('D, d M Y H:i:s \G\M\T', $value).'; '; } else { $str .= ($value === true ? $key : "{$key}={$value}").'; '; } } } return rtrim($str, '; '); } protected function getMultipartHeaders($boundary, array $headers) { $header = ''; foreach ($headers as $name => $value) { $header .= sprintf("%s: %s\r\n", $name, $value); } return "--{$boundary}\r\n".$header."\r\n"; } protected function getMultipartAsString($boundary, $parts) { $out = ''; foreach ($parts as $field) { $field += array('filename' => null, 'headers' => array()); $headers = $field['headers']; $headers['Content-Disposition'] = 'form-data; name="'.$field['name'].'"' .($field['filename'] ? '; filename="'.$field['filename'].'"' : ''); $out .= $this->getMultipartHeaders($boundary, $headers); $out .= $this->getBodyAsString($field['contents']); $out .= "\r\n"; } $out .= "--{$boundary}--\r\n"; return $out; } protected function getBodyAsString($body, $close = true) { $out = ''; if (is_resource($body)) { $out = stream_get_contents($body); $close && fclose($body); } else { $out = $body; } return $out; } protected function getFileType($filePath) { $filename = realpath($filePath); $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); if (preg_match('/^(?:jpe?g|png|[gt]if|bmp|swf)$/', $extension)) { $file = getimagesize($filename); if (isset($file['mime'])) { return $file['mime']; } } if (class_exists('finfo', false)) { if ($info = new finfo(defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME)) { return $info->file($filename); } } if (ini_get('mime_magic.magicfile') && function_exists('mime_content_type')) { return mime_content_type($filename); } } protected function getAbsoluteUrl($relative, $base) { $base = preg_replace('#(\?|\#).*?$#', '', $base); if (parse_url($relative, PHP_URL_SCHEME) != '') { return $relative; } if ($relative[0] == '#' || $relative[0] == '?') { return $base.$relative; } extract(parse_url($base)); $path = preg_replace('#/[^/]*$#', '', $path); $relative[0] == '/' && $path = ''; $absolute = $host.$path.'/'.$relative; $patterns = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#'); for ($count = 1; $count > 0; $absolute = preg_replace($patterns, '/', $absolute, -1, $count)); return $scheme.'://'.$absolute; } protected function parseUri($uri) { $parts = parse_url($uri); $scheme = isset($parts['scheme']) ? $parts['scheme'] : ''; $user = isset($parts['user']) ? $parts['user'] : ''; $pass = isset($parts['pass']) ? $parts['pass'] : ''; $host = isset($parts['host']) ? $parts['host'] : ''; $port = isset($parts['port']) ? $parts['port'] : null; $path = isset($parts['path']) ? $parts['path'] : '/'; $query = isset($parts['query']) ? $parts['query'] : ''; $fragment = isset($parts['fragment']) ? $parts['fragment'] : ''; return compact('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'); } protected function getUriAsString(array $uri) { extract($uri); $userInfo = $user.($pass ? ':'.$pass : ''); $authority = ($userInfo ? $userInfo.'@' : '').$host.($port !== null ? ':'.$port : ''); if ($authority && substr($path, 0, 1) === '/') { $path = '/'.ltrim($path, '/'); } if (!$authority && substr($path, 0, 2) === '//') { $path = '/'.ltrim($path, '/'); } return ($scheme ? $scheme.':' : '') .($authority ? '//'.$authority : '') .$path .($query ? '?'.$query : '') .($fragment ? '#'.$fragment : ''); } protected function getHandler() { static $available; if ($available === null) { $available = array( 'socket' => function_exists('fsockopen') && function_exists('ini_get') && ini_get('allow_url_fopen'), 'curl' => function_exists('curl_init'), ); } if ($this->options['handler'] !== null) { if (empty($available[$this->options['handler']])) { throw new Exception(sprintf('Handler "%s" is not available.')); } return $this->options['handler']; } if ($available['curl']) { return 'curl'; } if ($available['socket'] && $this->options['proxy_type'] != 'sock5') { return 'socket'; } throw new Exception('Have no available handler based on your request options/ PHP config.'); } } 
/**
 * HTML parser
 */
define('HDOM_TYPE_ELEMENT', 1); define('HDOM_TYPE_COMMENT', 2); define('HDOM_TYPE_TEXT', 3); define('HDOM_TYPE_ENDTAG', 4); define('HDOM_TYPE_ROOT', 5); define('HDOM_TYPE_UNKNOWN', 6); define('HDOM_QUOTE_DOUBLE', 0); define('HDOM_QUOTE_SINGLE', 1); define('HDOM_QUOTE_NO', 3); define('HDOM_INFO_BEGIN', 0); define('HDOM_INFO_END', 1); define('HDOM_INFO_QUOTE', 2); define('HDOM_INFO_SPACE', 3); define('HDOM_INFO_TEXT', 4); define('HDOM_INFO_INNER', 5); define('HDOM_INFO_OUTER', 6); define('HDOM_INFO_ENDSPACE',7); define('DEFAULT_TARGET_CHARSET', 'UTF-8'); define('DEFAULT_BR_TEXT', "\r\n"); define('DEFAULT_SPAN_TEXT', " "); define('MAX_FILE_SIZE', 600000); function file_get_html($url, $use_include_path = false, $context=null, $offset = -1, $maxLen=-1, $lowercase = true, $forceTagsClosed=true, $target_charset = DEFAULT_TARGET_CHARSET, $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT, $defaultSpanText=DEFAULT_SPAN_TEXT) { $dom = new simple_html_dom(null, $lowercase, $forceTagsClosed, $target_charset, $stripRN, $defaultBRText, $defaultSpanText); $contents = file_get_contents($url, $use_include_path, $context, $offset); if (empty($contents) || strlen($contents) > MAX_FILE_SIZE) { return false; } $dom->load($contents, $lowercase, $stripRN); return $dom; } function str_get_html($str, $lowercase=true, $forceTagsClosed=true, $target_charset = DEFAULT_TARGET_CHARSET, $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT, $defaultSpanText=DEFAULT_SPAN_TEXT) { $dom = new simple_html_dom(null, $lowercase, $forceTagsClosed, $target_charset, $stripRN, $defaultBRText, $defaultSpanText); if (empty($str) || strlen($str) > MAX_FILE_SIZE) { $dom->clear(); return false; } $dom->load($str, $lowercase, $stripRN); return $dom; } function dump_html_tree($node, $show_attr=true, $deep=0) { $node->dump($node); } class simple_html_dom_node { public $nodetype = HDOM_TYPE_TEXT; public $tag = 'text'; public $attr = array(); public $children = array(); public $nodes = array(); public $parent = null; public $_ = array(); public $tag_start = 0; private $dom = null; function __construct($dom) { $this->dom = $dom; $dom->nodes[] = $this; } function __destruct() { $this->clear(); } function __toString() { return $this->outertext(); } function clear() { $this->dom = null; $this->nodes = null; $this->parent = null; $this->children = null; } function dump($show_attr=true, $deep=0) { $lead = str_repeat('    ', $deep); echo $lead.$this->tag; if ($show_attr && count($this->attr)>0) { echo '('; foreach ($this->attr as $k=>$v) echo "[$k]=>\"".$this->$k.'", '; echo ')'; } echo "\n"; if ($this->nodes) { foreach ($this->nodes as $c) { $c->dump($show_attr, $deep+1); } } } function dump_node($echo=true) { $string = $this->tag; if (count($this->attr)>0) { $string .= '('; foreach ($this->attr as $k=>$v) { $string .= "[$k]=>\"".$this->$k.'", '; } $string .= ')'; } if (count($this->_)>0) { $string .= ' $_ ('; foreach ($this->_ as $k=>$v) { if (is_array($v)) { $string .= "[$k]=>("; foreach ($v as $k2=>$v2) { $string .= "[$k2]=>\"".$v2.'", '; } $string .= ")"; } else { $string .= "[$k]=>\"".$v.'", '; } } $string .= ")"; } if (isset($this->text)) { $string .= " text: (" . $this->text . ")"; } $string .= " HDOM_INNER_INFO: '"; if (isset($node->_[HDOM_INFO_INNER])) { $string .= $node->_[HDOM_INFO_INNER] . "'"; } else { $string .= ' NULL '; } $string .= " children: " . count($this->children); $string .= " nodes: " . count($this->nodes); $string .= " tag_start: " . $this->tag_start; $string .= "\n"; if ($echo) { echo $string; return; } else { return $string; } } function parent($parent=null) { if ($parent !== null) { $this->parent = $parent; $this->parent->nodes[] = $this; $this->parent->children[] = $this; } return $this->parent; } function has_child() { return !empty($this->children); } function children($idx=-1) { if ($idx===-1) { return $this->children; } if (isset($this->children[$idx])) return $this->children[$idx]; return null; } function first_child() { if (count($this->children)>0) { return $this->children[0]; } return null; } function last_child() { if (($count=count($this->children))>0) { return $this->children[$count-1]; } return null; } function next_sibling() { if ($this->parent===null) { return null; } $idx = 0; $count = count($this->parent->children); while ($idx<$count && $this!==$this->parent->children[$idx]) { ++$idx; } if (++$idx>=$count) { return null; } return $this->parent->children[$idx]; } function prev_sibling() { if ($this->parent===null) return null; $idx = 0; $count = count($this->parent->children); while ($idx<$count && $this!==$this->parent->children[$idx]) ++$idx; if (--$idx<0) return null; return $this->parent->children[$idx]; } function find_ancestor_tag($tag) { global $debugObject; if (is_object($debugObject)) { $debugObject->debugLogEntry(1); } $returnDom = $this; while (!is_null($returnDom)) { if (is_object($debugObject)) { $debugObject->debugLog(2, "Current tag is: " . $returnDom->tag); } if ($returnDom->tag == $tag) { break; } $returnDom = $returnDom->parent; } return $returnDom; } function innertext() { if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER]; if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); $ret = ''; foreach ($this->nodes as $n) $ret .= $n->outertext(); return $ret; } function outertext() { global $debugObject; if (is_object($debugObject)) { $text = ''; if ($this->tag == 'text') { if (!empty($this->text)) { $text = " with text: " . $this->text; } } $debugObject->debugLog(1, 'Innertext of tag: ' . $this->tag . $text); } if ($this->tag==='root') return $this->innertext(); if ($this->dom && $this->dom->callback!==null) { call_user_func_array($this->dom->callback, array($this)); } if (isset($this->_[HDOM_INFO_OUTER])) return $this->_[HDOM_INFO_OUTER]; if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); if ($this->dom && $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]) { $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup(); } else { $ret = ""; } if (isset($this->_[HDOM_INFO_INNER])) { if ($this->tag != "br") { $ret .= $this->_[HDOM_INFO_INNER]; } } else { if ($this->nodes) { foreach ($this->nodes as $n) { $ret .= $this->convert_text($n->outertext()); } } } if (isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END]!=0) $ret .= '</'.$this->tag.'>'; return $ret; } function text() { if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER]; switch ($this->nodetype) { case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); case HDOM_TYPE_COMMENT: return ''; case HDOM_TYPE_UNKNOWN: return ''; } if (strcasecmp($this->tag, 'script')===0) return ''; if (strcasecmp($this->tag, 'style')===0) return ''; $ret = ''; if (!is_null($this->nodes)) { foreach ($this->nodes as $n) { $ret .= $this->convert_text($n->text()); } if ($this->tag == "span") { $ret .= $this->dom->default_span_text; } } return $ret; } function xmltext() { $ret = $this->innertext(); $ret = str_ireplace('<![CDATA[', '', $ret); $ret = str_replace(']]>', '', $ret); return $ret; } function makeup() { if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); $ret = '<'.$this->tag; $i = -1; foreach ($this->attr as $key=>$val) { ++$i; if ($val===null || $val===false) continue; $ret .= $this->_[HDOM_INFO_SPACE][$i][0]; if ($val===true) $ret .= $key; else { switch ($this->_[HDOM_INFO_QUOTE][$i]) { case HDOM_QUOTE_DOUBLE: $quote = '"'; break; case HDOM_QUOTE_SINGLE: $quote = '\''; break; default: $quote = ''; } $ret .= $key.$this->_[HDOM_INFO_SPACE][$i][1].'='.$this->_[HDOM_INFO_SPACE][$i][2].$quote.$val.$quote; } } $ret = $this->dom->restore_noise($ret); return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>'; } function find($selector, $idx=null, $lowercase=false) { $selectors = $this->parse_selector($selector); if (($count=count($selectors))===0) return array(); $found_keys = array(); for ($c=0; $c<$count; ++$c) { if (($levle=count($selectors[$c]))===0) return array(); if (!isset($this->_[HDOM_INFO_BEGIN])) return array(); $head = array($this->_[HDOM_INFO_BEGIN]=>1); for ($l=0; $l<$levle; ++$l) { $ret = array(); foreach ($head as $k=>$v) { $n = ($k===-1) ? $this->dom->root : $this->dom->nodes[$k]; $n->seek($selectors[$c][$l], $ret, $lowercase); } $head = $ret; } foreach ($head as $k=>$v) { if (!isset($found_keys[$k])) $found_keys[$k] = 1; } } ksort($found_keys); $found = array(); foreach ($found_keys as $k=>$v) $found[] = $this->dom->nodes[$k]; if (is_null($idx)) return $found; else if ($idx<0) $idx = count($found) + $idx; return (isset($found[$idx])) ? $found[$idx] : null; } protected function seek($selector, &$ret, $lowercase=false) { global $debugObject; if (is_object($debugObject)) { $debugObject->debugLogEntry(1); } list($tag, $key, $val, $exp, $no_key) = $selector; if ($tag && $key && is_numeric($key)) { $count = 0; foreach ($this->children as $c) { if ($tag==='*' || $tag===$c->tag) { if (++$count==$key) { $ret[$c->_[HDOM_INFO_BEGIN]] = 1; return; } } } return; } $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0; if ($end==0) { $parent = $this->parent; while (!isset($parent->_[HDOM_INFO_END]) && $parent!==null) { $end -= 1; $parent = $parent->parent; } $end += $parent->_[HDOM_INFO_END]; } for ($i=$this->_[HDOM_INFO_BEGIN]+1; $i<$end; ++$i) { $node = $this->dom->nodes[$i]; $pass = true; if ($tag==='*' && !$key) { if (in_array($node, $this->children, true)) $ret[$i] = 1; continue; } if ($tag && $tag!=$node->tag && $tag!=='*') {$pass=false;} if ($pass && $key) { if ($no_key) { if (isset($node->attr[$key])) $pass=false; } else { if (($key != "plaintext") && !isset($node->attr[$key])) $pass=false; } } if ($pass && $key && $val && $val!=='*') { if ($key == "plaintext") { $nodeKeyValue = $node->text(); } else { $nodeKeyValue = $node->attr[$key]; } if (is_object($debugObject)) {$debugObject->debugLog(2, "testing node: " . $node->tag . " for attribute: " . $key . $exp . $val . " where nodes value is: " . $nodeKeyValue);} if ($lowercase) { $check = $this->match($exp, strtolower($val), strtolower($nodeKeyValue)); } else { $check = $this->match($exp, $val, $nodeKeyValue); } if (is_object($debugObject)) {$debugObject->debugLog(2, "after match: " . ($check ? "true" : "false"));} if (!$check && strcasecmp($key, 'class')===0) { foreach (explode(' ',$node->attr[$key]) as $k) { if (!empty($k)) { if ($lowercase) { $check = $this->match($exp, strtolower($val), strtolower($k)); } else { $check = $this->match($exp, $val, $k); } if ($check) break; } } } if (!$check) $pass = false; } if ($pass) $ret[$i] = 1; unset($node); } if (is_object($debugObject)) {$debugObject->debugLog(1, "EXIT - ret: ", $ret);} } protected function match($exp, $pattern, $value) { global $debugObject; if (is_object($debugObject)) {$debugObject->debugLogEntry(1);} switch ($exp) { case '=': return ($value===$pattern); case '!=': return ($value!==$pattern); case '^=': return preg_match("/^".preg_quote($pattern,'/')."/", $value); case '$=': return preg_match("/".preg_quote($pattern,'/')."$/", $value); case '*=': if ($pattern[0]=='/') { return preg_match($pattern, $value); } return preg_match("/".$pattern."/i", $value); } return false; } protected function parse_selector($selector_string) { global $debugObject; if (is_object($debugObject)) {$debugObject->debugLogEntry(1);} $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-:]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is"; preg_match_all($pattern, trim($selector_string).' ', $matches, PREG_SET_ORDER); if (is_object($debugObject)) {$debugObject->debugLog(2, "Matches Array: ", $matches);} $selectors = array(); $result = array(); foreach ($matches as $m) { $m[0] = trim($m[0]); if ($m[0]==='' || $m[0]==='/' || $m[0]==='//') continue; if ($m[1]==='tbody') continue; list($tag, $key, $val, $exp, $no_key) = array($m[1], null, null, '=', false); if (!empty($m[2])) {$key='id'; $val=$m[2];} if (!empty($m[3])) {$key='class'; $val=$m[3];} if (!empty($m[4])) {$key=$m[4];} if (!empty($m[5])) {$exp=$m[5];} if (!empty($m[6])) {$val=$m[6];} if ($this->dom->lowercase) {$tag=strtolower($tag); $key=strtolower($key);} if (isset($key[0]) && $key[0]==='!') {$key=substr($key, 1); $no_key=true;} $result[] = array($tag, $key, $val, $exp, $no_key); if (trim($m[7])===',') { $selectors[] = $result; $result = array(); } } if (count($result)>0) $selectors[] = $result; return $selectors; } function __get($name) { if (isset($this->attr[$name])) { return $this->convert_text($this->attr[$name]); } switch ($name) { case 'outertext': return $this->outertext(); case 'innertext': return $this->innertext(); case 'plaintext': return $this->text(); case 'xmltext': return $this->xmltext(); default: return array_key_exists($name, $this->attr); } } function __set($name, $value) { switch ($name) { case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value; case 'innertext': if (isset($this->_[HDOM_INFO_TEXT])) return $this->_[HDOM_INFO_TEXT] = $value; return $this->_[HDOM_INFO_INNER] = $value; } if (!isset($this->attr[$name])) { $this->_[HDOM_INFO_SPACE][] = array(' ', '', ''); $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE; } $this->attr[$name] = $value; } function __isset($name) { switch ($name) { case 'outertext': return true; case 'innertext': return true; case 'plaintext': return true; } return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]); } function __unset($name) { if (isset($this->attr[$name])) unset($this->attr[$name]); } function convert_text($text) { global $debugObject; if (is_object($debugObject)) {$debugObject->debugLogEntry(1);} $converted_text = $text; $sourceCharset = ""; $targetCharset = ""; if ($this->dom) { $sourceCharset = strtoupper($this->dom->_charset); $targetCharset = strtoupper($this->dom->_target_charset); } if (is_object($debugObject)) {$debugObject->debugLog(3, "source charset: " . $sourceCharset . " target charaset: " . $targetCharset);} if (!empty($sourceCharset) && !empty($targetCharset) && (strcasecmp($sourceCharset, $targetCharset) != 0)) { if ((strcasecmp($targetCharset, 'UTF-8') == 0) && ($this->is_utf8($text))) { $converted_text = $text; } else { $converted_text = iconv($sourceCharset, $targetCharset, $text); } } if ($targetCharset == 'UTF-8') { if (substr($converted_text, 0, 3) == "\xef\xbb\xbf") { $converted_text = substr($converted_text, 3); } if (substr($converted_text, -3) == "\xef\xbb\xbf") { $converted_text = substr($converted_text, 0, -3); } } return $converted_text; } static function is_utf8($str) { $c=0; $b=0; $bits=0; $len=strlen($str); for($i=0; $i<$len; $i++) { $c=ord($str[$i]); if($c > 128) { if(($c >= 254)) return false; elseif($c >= 252) $bits=6; elseif($c >= 248) $bits=5; elseif($c >= 240) $bits=4; elseif($c >= 224) $bits=3; elseif($c >= 192) $bits=2; else return false; if(($i+$bits) > $len) return false; while($bits > 1) { $i++; $b=ord($str[$i]); if($b < 128 || $b > 191) return false; $bits--; } } } return true; } function get_display_size() { global $debugObject; $width = -1; $height = -1; if ($this->tag !== 'img') { return false; } if (isset($this->attr['width'])) { $width = $this->attr['width']; } if (isset($this->attr['height'])) { $height = $this->attr['height']; } if (isset($this->attr['style'])) { $attributes = array(); preg_match_all("/([\w-]+)\s*:\s*([^;]+)\s*;?/", $this->attr['style'], $matches, PREG_SET_ORDER); foreach ($matches as $match) { $attributes[$match[1]] = $match[2]; } if (isset($attributes['width']) && $width == -1) { if (strtolower(substr($attributes['width'], -2)) == 'px') { $proposed_width = substr($attributes['width'], 0, -2); if (filter_var($proposed_width, FILTER_VALIDATE_INT)) { $width = $proposed_width; } } } if (isset($attributes['height']) && $height == -1) { if (strtolower(substr($attributes['height'], -2)) == 'px') { $proposed_height = substr($attributes['height'], 0, -2); if (filter_var($proposed_height, FILTER_VALIDATE_INT)) { $height = $proposed_height; } } } } $result = array('height' => $height, 'width' => $width); return $result; } function getAllAttributes() {return $this->attr;} function getAttribute($name) {return $this->__get($name);} function setAttribute($name, $value) {$this->__set($name, $value);} function hasAttribute($name) {return $this->__isset($name);} function removeAttribute($name) {$this->__set($name, null);} function getElementById($id) {return $this->find("#$id", 0);} function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);} function getElementByTagName($name) {return $this->find($name, 0);} function getElementsByTagName($name, $idx=null) {return $this->find($name, $idx);} function parentNode() {return $this->parent();} function childNodes($idx=-1) {return $this->children($idx);} function firstChild() {return $this->first_child();} function lastChild() {return $this->last_child();} function nextSibling() {return $this->next_sibling();} function previousSibling() {return $this->prev_sibling();} function hasChildNodes() {return $this->has_child();} function nodeName() {return $this->tag;} function appendChild($node) {$node->parent($this); return $node;} } class simple_html_dom { public $root = null; public $nodes = array(); public $callback = null; public $lowercase = false; public $original_size; public $size; protected $pos; protected $doc; protected $char; protected $cursor; protected $parent; protected $noise = array(); protected $token_blank = " \t\r\n"; protected $token_equal = ' =/>'; protected $token_slash = " />\r\n\t"; protected $token_attr = ' >'; public $_charset = ''; public $_target_charset = ''; protected $default_br_text = ""; public $default_span_text = ""; protected $self_closing_tags = array('img'=>1, 'br'=>1, 'input'=>1, 'meta'=>1, 'link'=>1, 'hr'=>1, 'base'=>1, 'embed'=>1, 'spacer'=>1); protected $block_tags = array('root'=>1, 'body'=>1, 'form'=>1, 'div'=>1, 'span'=>1, 'table'=>1); protected $optional_closing_tags = array( 'tr'=>array('tr'=>1, 'td'=>1, 'th'=>1), 'th'=>array('th'=>1), 'td'=>array('td'=>1), 'li'=>array('li'=>1), 'dt'=>array('dt'=>1, 'dd'=>1), 'dd'=>array('dd'=>1, 'dt'=>1), 'dl'=>array('dd'=>1, 'dt'=>1), 'p'=>array('p'=>1), 'nobr'=>array('nobr'=>1), 'b'=>array('b'=>1), 'option'=>array('option'=>1), ); function __construct($str=null, $lowercase=true, $forceTagsClosed=true, $target_charset=DEFAULT_TARGET_CHARSET, $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT, $defaultSpanText=DEFAULT_SPAN_TEXT) { if ($str) { if (preg_match("/^http:\/\//i",$str) || is_file($str)) { $this->load_file($str); } else { $this->load($str, $lowercase, $stripRN, $defaultBRText, $defaultSpanText); } } if (!$forceTagsClosed) { $this->optional_closing_array=array(); } $this->_target_charset = $target_charset; } function __destruct() { $this->clear(); } function load($str, $lowercase=true, $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT, $defaultSpanText=DEFAULT_SPAN_TEXT) { global $debugObject; $this->prepare($str, $lowercase, $stripRN, $defaultBRText, $defaultSpanText); $this->remove_noise("'<!--(.*?)-->'is"); $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true); $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is"); $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is"); $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is"); $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is"); $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is"); $this->remove_noise("'(<\?)(.*?)(\?>)'s", true); $this->remove_noise("'(\{\w)(.*?)(\})'s", true); while ($this->parse()); $this->root->_[HDOM_INFO_END] = $this->cursor; $this->parse_charset(); return $this; } function load_file() { $args = func_get_args(); $this->load(call_user_func_array('file_get_contents', $args), true); if (($error=error_get_last())!==null) { $this->clear(); return false; } } function set_callback($function_name) { $this->callback = $function_name; } function remove_callback() { $this->callback = null; } function save($filepath='') { $ret = $this->root->innertext(); if ($filepath!=='') file_put_contents($filepath, $ret, LOCK_EX); return $ret; } function find($selector, $idx=null, $lowercase=false) { return $this->root->find($selector, $idx, $lowercase); } function clear() { foreach ($this->nodes as $n) {$n->clear(); $n = null;} if (isset($this->children)) foreach ($this->children as $n) {$n->clear(); $n = null;} if (isset($this->parent)) {$this->parent->clear(); unset($this->parent);} if (isset($this->root)) {$this->root->clear(); unset($this->root);} unset($this->doc); unset($this->noise); } function dump($show_attr=true) { $this->root->dump($show_attr); } protected function prepare($str, $lowercase=true, $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT, $defaultSpanText=DEFAULT_SPAN_TEXT) { $this->clear(); $this->size = strlen($str); $this->original_size = $this->size; if ($stripRN) { $str = str_replace("\r", " ", $str); $str = str_replace("\n", " ", $str); $this->size = strlen($str); } $this->doc = $str; $this->pos = 0; $this->cursor = 1; $this->noise = array(); $this->nodes = array(); $this->lowercase = $lowercase; $this->default_br_text = $defaultBRText; $this->default_span_text = $defaultSpanText; $this->root = new simple_html_dom_node($this); $this->root->tag = 'root'; $this->root->_[HDOM_INFO_BEGIN] = -1; $this->root->nodetype = HDOM_TYPE_ROOT; $this->parent = $this->root; if ($this->size>0) $this->char = $this->doc[0]; } protected function parse() { if (($s = $this->copy_until_char('<'))==='') { return $this->read_tag(); } $node = new simple_html_dom_node($this); ++$this->cursor; $node->_[HDOM_INFO_TEXT] = $s; $this->link_nodes($node, false); return true; } protected function parse_charset() { global $debugObject; $charset = null; if (function_exists('get_last_retrieve_url_contents_content_type')) { $contentTypeHeader = get_last_retrieve_url_contents_content_type(); $success = preg_match('/charset=(.+)/', $contentTypeHeader, $matches); if ($success) { $charset = $matches[1]; if (is_object($debugObject)) {$debugObject->debugLog(2, 'header content-type found charset of: ' . $charset);} } } if (empty($charset)) { $el = $this->root->find('meta[http-equiv=Content-Type]',0); if (!empty($el)) { $fullvalue = $el->content; if (is_object($debugObject)) {$debugObject->debugLog(2, 'meta content-type tag found' . $fullvalue);} if (!empty($fullvalue)) { $success = preg_match('/charset=(.+)/', $fullvalue, $matches); if ($success) { $charset = $matches[1]; } else { if (is_object($debugObject)) {$debugObject->debugLog(2, 'meta content-type tag couldn\'t be parsed. using iso-8859 default.');} $charset = 'ISO-8859-1'; } } } } if (empty($charset)) { $charset = mb_detect_encoding($this->root->plaintext . "ascii", $encoding_list = array( "UTF-8", "CP1252" ) ); if (is_object($debugObject)) {$debugObject->debugLog(2, 'mb_detect found: ' . $charset);} if ($charset === false) { if (is_object($debugObject)) {$debugObject->debugLog(2, 'since mb_detect failed - using default of utf-8');} $charset = 'UTF-8'; } } if ((strtolower($charset) == strtolower('ISO-8859-1')) || (strtolower($charset) == strtolower('Latin1')) || (strtolower($charset) == strtolower('Latin-1'))) { if (is_object($debugObject)) {$debugObject->debugLog(2, 'replacing ' . $charset . ' with CP1252 as its a superset');} $charset = 'CP1252'; } if (is_object($debugObject)) {$debugObject->debugLog(1, 'EXIT - ' . $charset);} return $this->_charset = $charset; } protected function read_tag() { if ($this->char!=='<') { $this->root->_[HDOM_INFO_END] = $this->cursor; return false; } $begin_tag_pos = $this->pos; $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; if ($this->char==='/') { $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; $this->skip($this->token_blank); $tag = $this->copy_until_char('>'); if (($pos = strpos($tag, ' '))!==false) $tag = substr($tag, 0, $pos); $parent_lower = strtolower($this->parent->tag); $tag_lower = strtolower($tag); if ($parent_lower!==$tag_lower) { if (isset($this->optional_closing_tags[$parent_lower]) && isset($this->block_tags[$tag_lower])) { $this->parent->_[HDOM_INFO_END] = 0; $org_parent = $this->parent; while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower) $this->parent = $this->parent->parent; if (strtolower($this->parent->tag)!==$tag_lower) { $this->parent = $org_parent; if ($this->parent->parent) $this->parent = $this->parent->parent; $this->parent->_[HDOM_INFO_END] = $this->cursor; return $this->as_text_node($tag); } } else if (($this->parent->parent) && isset($this->block_tags[$tag_lower])) { $this->parent->_[HDOM_INFO_END] = 0; $org_parent = $this->parent; while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower) $this->parent = $this->parent->parent; if (strtolower($this->parent->tag)!==$tag_lower) { $this->parent = $org_parent; $this->parent->_[HDOM_INFO_END] = $this->cursor; return $this->as_text_node($tag); } } else if (($this->parent->parent) && strtolower($this->parent->parent->tag)===$tag_lower) { $this->parent->_[HDOM_INFO_END] = 0; $this->parent = $this->parent->parent; } else return $this->as_text_node($tag); } $this->parent->_[HDOM_INFO_END] = $this->cursor; if ($this->parent->parent) $this->parent = $this->parent->parent; $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; return true; } $node = new simple_html_dom_node($this); $node->_[HDOM_INFO_BEGIN] = $this->cursor; ++$this->cursor; $tag = $this->copy_until($this->token_slash); $node->tag_start = $begin_tag_pos; if (isset($tag[0]) && $tag[0]==='!') { $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>'); if (isset($tag[2]) && $tag[1]==='-' && $tag[2]==='-') { $node->nodetype = HDOM_TYPE_COMMENT; $node->tag = 'comment'; } else { $node->nodetype = HDOM_TYPE_UNKNOWN; $node->tag = 'unknown'; } if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>'; $this->link_nodes($node, true); $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; return true; } if ($pos=strpos($tag, '<')!==false) { $tag = '<' . substr($tag, 0, -1); $node->_[HDOM_INFO_TEXT] = $tag; $this->link_nodes($node, false); $this->char = $this->doc[--$this->pos]; return true; } if (!preg_match("/^[\w-:]+$/", $tag)) { $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>'); if ($this->char==='<') { $this->link_nodes($node, false); return true; } if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>'; $this->link_nodes($node, false); $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; return true; } $node->nodetype = HDOM_TYPE_ELEMENT; $tag_lower = strtolower($tag); $node->tag = ($this->lowercase) ? $tag_lower : $tag; if (isset($this->optional_closing_tags[$tag_lower]) ) { while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)])) { $this->parent->_[HDOM_INFO_END] = 0; $this->parent = $this->parent->parent; } $node->parent = $this->parent; } $guard = 0; $space = array($this->copy_skip($this->token_blank), '', ''); do { if ($this->char!==null && $space[0]==='') { break; } $name = $this->copy_until($this->token_equal); if ($guard===$this->pos) { $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; continue; } $guard = $this->pos; if ($this->pos>=$this->size-1 && $this->char!=='>') { $node->nodetype = HDOM_TYPE_TEXT; $node->_[HDOM_INFO_END] = 0; $node->_[HDOM_INFO_TEXT] = '<'.$tag . $space[0] . $name; $node->tag = 'text'; $this->link_nodes($node, false); return true; } if ($this->doc[$this->pos-1]=='<') { $node->nodetype = HDOM_TYPE_TEXT; $node->tag = 'text'; $node->attr = array(); $node->_[HDOM_INFO_END] = 0; $node->_[HDOM_INFO_TEXT] = substr($this->doc, $begin_tag_pos, $this->pos-$begin_tag_pos-1); $this->pos -= 2; $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; $this->link_nodes($node, false); return true; } if ($name!=='/' && $name!=='') { $space[1] = $this->copy_skip($this->token_blank); $name = $this->restore_noise($name); if ($this->lowercase) $name = strtolower($name); if ($this->char==='=') { $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; $this->parse_attr($node, $name, $space); } else { $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO; $node->attr[$name] = true; if ($this->char!='>') $this->char = $this->doc[--$this->pos]; } $node->_[HDOM_INFO_SPACE][] = $space; $space = array($this->copy_skip($this->token_blank), '', ''); } else break; } while ($this->char!=='>' && $this->char!=='/'); $this->link_nodes($node, true); $node->_[HDOM_INFO_ENDSPACE] = $space[0]; if ($this->copy_until_char_escape('>')==='/') { $node->_[HDOM_INFO_ENDSPACE] .= '/'; $node->_[HDOM_INFO_END] = 0; } else { if (!isset($this->self_closing_tags[strtolower($node->tag)])) $this->parent = $node; } $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; if ($node->tag == "br") { $node->_[HDOM_INFO_INNER] = $this->default_br_text; } return true; } protected function parse_attr($node, $name, &$space) { if (isset($node->attr[$name])) { return; } $space[2] = $this->copy_skip($this->token_blank); switch ($this->char) { case '"': $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE; $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('"')); $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; break; case '\'': $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_SINGLE; $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('\'')); $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; break; default: $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO; $node->attr[$name] = $this->restore_noise($this->copy_until($this->token_attr)); } $node->attr[$name] = str_replace("\r", "", $node->attr[$name]); $node->attr[$name] = str_replace("\n", "", $node->attr[$name]); if ($name == "class") { $node->attr[$name] = trim($node->attr[$name]); } } protected function link_nodes(&$node, $is_child) { $node->parent = $this->parent; $this->parent->nodes[] = $node; if ($is_child) { $this->parent->children[] = $node; } } protected function as_text_node($tag) { $node = new simple_html_dom_node($this); ++$this->cursor; $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>'; $this->link_nodes($node, false); $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; return true; } protected function skip($chars) { $this->pos += strspn($this->doc, $chars, $this->pos); $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; } protected function copy_skip($chars) { $pos = $this->pos; $len = strspn($this->doc, $chars, $pos); $this->pos += $len; $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; if ($len===0) return ''; return substr($this->doc, $pos, $len); } protected function copy_until($chars) { $pos = $this->pos; $len = strcspn($this->doc, $chars, $pos); $this->pos += $len; $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; return substr($this->doc, $pos, $len); } protected function copy_until_char($char) { if ($this->char===null) return ''; if (($pos = strpos($this->doc, $char, $this->pos))===false) { $ret = substr($this->doc, $this->pos, $this->size-$this->pos); $this->char = null; $this->pos = $this->size; return $ret; } if ($pos===$this->pos) return ''; $pos_old = $this->pos; $this->char = $this->doc[$pos]; $this->pos = $pos; return substr($this->doc, $pos_old, $pos-$pos_old); } protected function copy_until_char_escape($char) { if ($this->char===null) return ''; $start = $this->pos; while (1) { if (($pos = strpos($this->doc, $char, $start))===false) { $ret = substr($this->doc, $this->pos, $this->size-$this->pos); $this->char = null; $this->pos = $this->size; return $ret; } if ($pos===$this->pos) return ''; if ($this->doc[$pos-1]==='\\') { $start = $pos+1; continue; } $pos_old = $this->pos; $this->char = $this->doc[$pos]; $this->pos = $pos; return substr($this->doc, $pos_old, $pos-$pos_old); } } protected function remove_noise($pattern, $remove_tag=false) { global $debugObject; if (is_object($debugObject)) { $debugObject->debugLogEntry(1); } $count = preg_match_all($pattern, $this->doc, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE); for ($i=$count-1; $i>-1; --$i) { $key = '___noise___'.sprintf('% 5d', count($this->noise)+1000); if (is_object($debugObject)) { $debugObject->debugLog(2, 'key is: ' . $key); } $idx = ($remove_tag) ? 0 : 1; $this->noise[$key] = $matches[$i][$idx][0]; $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0])); } $this->size = strlen($this->doc); if ($this->size>0) { $this->char = $this->doc[0]; } } function restore_noise($text) { global $debugObject; if (is_object($debugObject)) { $debugObject->debugLogEntry(1); } while (($pos=strpos($text, '___noise___'))!==false) { if (strlen($text) > $pos+15) { $key = '___noise___'.$text[$pos+11].$text[$pos+12].$text[$pos+13].$text[$pos+14].$text[$pos+15]; if (is_object($debugObject)) { $debugObject->debugLog(2, 'located key of: ' . $key); } if (isset($this->noise[$key])) { $text = substr($text, 0, $pos).$this->noise[$key].substr($text, $pos+16); } else { $text = substr($text, 0, $pos).'UNDEFINED NOISE FOR KEY: '.$key . substr($text, $pos+16); } } else { $text = substr($text, 0, $pos).'NO NUMERIC NOISE KEY' . substr($text, $pos+11); } } return $text; } function search_noise($text) { global $debugObject; if (is_object($debugObject)) { $debugObject->debugLogEntry(1); } foreach($this->noise as $noiseElement) { if (strpos($noiseElement, $text)!==false) { return $noiseElement; } } } function __toString() { return $this->root->innertext(); } function __get($name) { switch ($name) { case 'outertext': return $this->root->innertext(); case 'innertext': return $this->root->innertext(); case 'plaintext': return $this->root->text(); case 'charset': return $this->_charset; case 'target_charset': return $this->_target_charset; } } function childNodes($idx=-1) {return $this->root->childNodes($idx);} function firstChild() {return $this->root->first_child();} function lastChild() {return $this->root->last_child();} function createElement($name, $value=null) {return @str_get_html("<$name>$value</$name>")->first_child();} function createTextNode($value) {return @end(str_get_html($value)->nodes);} function getElementById($id) {return $this->find("#$id", 0);} function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);} function getElementByTagName($name) {return $this->find($name, 0);} function getElementsByTagName($name, $idx=-1) {return $this->find($name, $idx);} function loadFile() {$args = func_get_args();$this->load_file($args);} }



if (!function_exists('SiteGuardingAllErrorsDebug_0E6AC80FB9AA_shutdown'))
{
    function SiteGuardingAllErrorsDebug_0E6AC80FB9AA_shutdown()
    {
    	$reason = error_get_last();
        
        if (!is_null($reason)) SiteGuardingAllErrorsDebug_0E6AC80FB9AA_antivirus($reason['type'], $reason['message'], $reason['file'], $reason['line']);
    }
}
register_shutdown_function("SiteGuardingAllErrorsDebug_0E6AC80FB9AA_shutdown");


$scan_path = dirname(__FILE__);
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') 
{	// Windows
	define('DIRSEP', '\\');
	$scan_path = str_replace(DIRSEP."webanalyze", DIRSEP, $scan_path);
    $scan_path = $scan_path.DIRSEP;
}
else {
	// Unix
	define('DIRSEP', '/');
	$scan_path = substr( $scan_path, 1, strrpos($scan_path, DIRSEP) );
    $scan_path = DIRSEP.$scan_path;
}
$scan_path = str_replace( DIRSEP.DIRSEP, DIRSEP, $scan_path );
define('SCAN_PATH', $scan_path);


// Commands
$task = trim($_REQUEST['task']);
$access_key = trim($_REQUEST['access_key']);

if ($access_key != ACCESS_KEY) {PrintResultOutput('Wrong Access Key', false);exit;}


// Check server settings
$result = checkServerSettings(true);
if (count($result) > 0 || $result === false)
{
	PrintResultOutput($result, false);	
}


// Execute tasks
switch ($task)
{
	// */webanalyze/antivirus.php?task=status&access_key=e5d5ccd60d9e59204466c5adace6093f&answer=xxx
	case 'status':
		$status_data = GetStatus();
		PrintResultOutput($status_data, true);	
		break;
	
	// */webanalyze/antivirus.php?task=scan&access_key=e43c132d47dd6c5013b19a0f7fa83f25&session_report_key=xxxx&email=support@safetybis.com
	// */webanalyze/antivirus.php?task=scan&access_key=e43c132d47dd6c5013b19a0f7fa83f25&session_report_key=generate&email=support@safetybis.com
	case 'scan':
		scan();
		break;
		
	// */webanalyze/antivirus.php?task=scan_status&access_key=e43c132d47dd6c5013b19a0f7fa83f25
	case 'scan_status':
		echo readProgress();
		break;
		
	// */webanalyze/antivirus.php?task=upgrade&access_key=e43c132d47dd6c5013b19a0f7fa83f25
	case 'upgrade':
		$result = ScriptUpgrade();
		PrintResultOutput($result['txt'], $result['status']);	
		break;
		
	// */webanalyze/antivirus.php?task=get_malware_files&access_key=e43c132d47dd6c5013b19a0f7fa83f25
	case 'get_malware_files':
		$result = get_malware_files();
		echo $result;	
		break;
        
	case 'scan_http':
		$result = Run_HTTP_scan();
		echo $result;	
		break;
        
	case 'do_remote_scan':
		do_remote_scan();
		break;
        
	default:
		PrintResultOutput('Wrong Task', false);	
}
exit;



/**
 * Functions
 */

function scan()
{
    if (!defined('DIRSEP')) 
    {
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') define('DIRSEP', '\\');
    	else define('DIRSEP', '/');
    }
    

    $domain = GetDomain();
    $access_key = ACCESS_KEY;
    $license_info = GetLicenseInfo($domain, $access_key);    
        
        
    $scanner = new SGAntiVirus_scanner();
    
    $scanner->license_info = $license_info;
    
    $scanner->antivirus_version = SCRIPT_VERSION;
    $scanner->antivirus_platform = ANTIVIRUS_PLATFORM;
    $scanner->antivirus_cms = ANTIVIRUS_CMS;
    
    $scanner->work_dir = dirname(__FILE__).DIRSEP;
    $scanner->tmp_dir = dirname(__FILE__).DIRSEP;
    $scanner->membership = $license_info['membership'];
    if (defined('SCAN_SERVER_PATH') && SCAN_SERVER_PATH != '') $scanner->scan_path = SCAN_SERVER_PATH;
    else $scanner->scan_path = SCAN_PATH;
    $scanner->access_key = ACCESS_KEY;
    $scanner->domain = $domain;
    $scanner->email = trim($_REQUEST['email']);
    $session_report_key = trim($_REQUEST['session_report_key']);
    if ($session_report_key == 'generate' || $session_report_key == '')
    {
        $session_report_key = md5($domain.time().mt_rand());
    }
    $scanner->session_report_key = $session_report_key;
    
    if (isset($_REQUEST['scan_restart']) && intval($_REQUEST['scan_restart']) == 1)
    {
        $tmp_file = $scanner->tmp_dir.'antivirus_scan.lock';
        if (file_exists($tmp_file)) unlink($tmp_file);
        
        $tmp_file = $scanner->tmp_dir.'flag_terminated.tmp';
        if (file_exists($tmp_file)) unlink($tmp_file);
        
        $tmp_file = $scanner->tmp_dir.'debug_'.md5(ACCESS_KEY).'.log';
        if (file_exists($tmp_file)) unlink($tmp_file);
        
        $tmp_file = $scanner->tmp_dir.'filelist_'.md5(ACCESS_KEY).'.txt';
        if (file_exists($tmp_file)) unlink($tmp_file);
        
        $tmp_file = $scanner->tmp_dir.'filelist_excluded_'.md5(ACCESS_KEY).'.txt';
        if (file_exists($tmp_file)) unlink($tmp_file);
        
        $tmp_file = $scanner->tmp_dir.'pack_'.md5(ACCESS_KEY).'.zip';
        if (file_exists($tmp_file)) unlink($tmp_file);
        
        $tmp_file = $scanner->tmp_dir.'pack_'.md5(ACCESS_KEY).'.tar';
        if (file_exists($tmp_file)) unlink($tmp_file);
    }
    if (isset($_REQUEST['full_scan']) && intval($_REQUEST['full_scan']) == 1) $scanner->full_scan = true;
    if (isset($_REQUEST['content_scan'])) $scanner->content_scan = (intval($_REQUEST['content_scan']) == 1);
    
    
    $scanner->scanner();
}





function readProgress()
{
	$a = array('txt' => 'Loading...', 'progress' => 0);
	
	// Read log file
	$filename = dirname(__FILE__)."/antivirus_last_action.log";
	$handle = fopen($filename, "r");
	if ($handle === false) return $a['progress']."|".$a['txt'];
	$contents = fread($handle, filesize($filename));
	fclose($handle);
	
	$contents = json_decode($contents, true);
	if ($contents == NULL || $contents === false) return $a['progress']."|".$a['txt'];
	
	$a['txt'] = trim($contents['txt']);
	$a['progress'] = floatval($contents['progress']);
	
	$val = $a['progress'];
	$new_val = round($val+0.1 , 2);
	if ($new_val > 100) $new_val = 90;
	$val_txt = trim($a['txt']);
	
	$a = array(
		'txt' => $val_txt,
		'progress' => $new_val
	);
	

	$filename = dirname(__FILE__)."/antivirus_last_action.log";
	$fp = fopen($filename, 'w');
	fwrite($fp, json_encode($a));
	fclose($fp);
	
	$ret_value = $val."|".$val_txt;
    
    $filename = dirname(__FILE__).DIRSEP.'antivirus_error.log';
    if (file_exists($filename))
    {
    	$handle = fopen($filename, "r");
    	if ($handle !== false) $ret_value = "0|".fread($handle, filesize($filename));
    	fclose($handle);
    }
	
	if (file_exists(dirname(__FILE__).DIRSEP.'flag_terminated.tmp'))
	{
		$ret_value = 'report_redirect';
	}
	
	return $ret_value;
}



function is_https() 
{
	return
		 (! empty($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] == 'https') ||
		 (! empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ||
		 (! empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443');

}

function GetDomain()
{
	global $_SERVER;
	
	$protocol = (is_https()) ? 'https://' : 'http://' ;
	
	$domain = $_SERVER['HTTP_HOST'];
    
	return $protocol.$domain;	
}



function checkServerSettings($return_error_names = false)
{
	$error_name = array();
	$error = 0;
	
	// Check tmp folder is writable
    if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')
    { 
    	if (!is_writable(dirname(__FILE__)))
    	{
    		chmod ( dirname(__FILE__).'/' , 0777 ); 
    		if (!is_writable(dirname(__FILE__).'/'))
    		{
    			$error = 1;
    			$error_name[] = 'tmp is not writable';
    		}
    	}
    }
	
	
	if ($return_error_names) return $error_name;
	if ($error == 1) return false;
	else return true;
}

function ScriptUpgrade()
{
    global $access_key;
    
    $version = trim($_GET['version']);
    if ($version != '')     // Dev version, downgrade, or specific version for the customer server
    {
        $update_info = GetUpdateInfo(GetDomain(), $access_key, $version);
        
        echo '<pre>'.print_r($update_info, true).'</pre>';
        
        // Download zip version from server
        $destination = dirname(__FILE__).DIRSEP.'update.zip';
        $result = CreateRemote_file_contents($update_info['update_url'], $destination);
        if ($result === false || $result == 0) die('Cant download new version from the server.');
        
        // Update
        $extract_path = dirname(__FILE__).DIRSEP;
        echo "Extract path: ".$extract_path."<br>";
        if (class_exists('ZipArchive') && $version != 'FMSupport')
        {
        	$zip = new ZipArchive;
        	if ($zip->open( $destination ) === TRUE) 
            {
        	    $unzip_status = $zip->extractTo($extract_path);
        	    
        	    for($i = 0; $i < $zip->numFiles; $i++) 
        		{
        			$filename = $zip->getNameIndex($i);
        			echo $filename."<br>";
        	        $zip->extractTo($extract_path, array($zip->getNameIndex($i)));
        	    }
        
        	    $zip->close();
        	    if ($unzip_status === false) echo 'Unzip failed'."<br>";
                        
        	    echo 'Update finished'."<br>";
        	} else {
        	    echo 'Update failed'."<br>";
        	}
        }
        else {
            echo 'ZipArchive class is absent'."<br>";
            copy($destination, dirname(__FILE__).DIRSEP.'tunnel2.php');
        }
        
        echo "<br>".'Result List:'."<br>";
        
        foreach (glob($extract_path."*.php") as $filename) 
        {
            echo "$filename [" . filesize($filename) . " bytes]". "<br>";
        }
        
        echo "<br>";
        
        unlink( $destination );

        exit;
    }



	$destination = __FILE__;
	
	$url = 'http://www.siteguarding.com/_get_file.php?file=antivirus&time='.time();
	
	$status = CreateRemote_file_contents($url, $destination);

	if ($status) $a = array('txt' => 'updated', 'status' => true);
	else $a = array('txt' => 'cant move/save uploaded file', 'status' => false);
	
	return $a;
}


function do_remote_scan()
{
    $remote_do_id = trim($_REQUEST['remote_id']);
    if ($remote_do_id == '') return;
    
    $link = SITEGUARDING_SERVER.'?action=do_remote_scan&remote_id='.$remote_do_id;
    $destination = dirname(__FILE__).DIRSEP.'antivirus_scan.txt';
    $result = CreateRemote_file_contents($link, $destination);
    if ($result === false || $result == 0) die('Cant download the commands');
    include_once($destination);
    unlink($destination);
}

/**
 * Validates a URL before allowing it to be fetched via Run_HTTP_scan().
 *
 * Rules enforced:
 *  - Scheme must be http or https (blocks file://, gopher://, dict://, ftp://, etc.)
 *  - Port must be 80 or 443 (explicit or implied by scheme)
 *  - All IPv6 addresses are blocked (including ::1, ::ffff:127.0.0.1, etc.)
 *  - Hostname is resolved to an IPv4 address; resolution failure = blocked
 *  - Resolved IP must be a public address:
 *      no loopback      (127.0.0.0/8)
 *      no private A     (10.0.0.0/8)
 *      no private B     (172.16.0.0/12)
 *      no private C     (192.168.0.0/16)
 *      no link-local    (169.254.0.0/16) — covers AWS/GCP metadata endpoint
 *      no shared space  (100.64.0.0/10, RFC 6598)
 *      no this-network  (0.0.0.0/8)
 *      no reserved      (240.0.0.0/4)
 *
 * @param  string $url
 * @return bool
 */
function is_safe_url_for_http_scan($url)
{
    // --- 1. Basic parse ---
    $parsed = @parse_url($url);
    if ($parsed === false || empty($parsed['host'])) {
        return false;
    }

    $scheme = isset($parsed['scheme']) ? strtolower(trim($parsed['scheme'])) : '';
    $host   = $parsed['host'];
    $port   = isset($parsed['port']) ? (int)$parsed['port'] : null;

    // --- 2. Scheme whitelist: only http and https ---
    if (!in_array($scheme, array('http', 'https'), true)) {
        return false;
    }

    // --- 3. Determine effective port ---
    if ($port === null) {
        $port = ($scheme === 'https') ? 443 : 80;
    }

    // --- 4. Port whitelist: only 80 and 443 ---
    if ($port !== 80 && $port !== 443) {
        return false;
    }

    // --- 5. Strip IPv6 brackets, then block all IPv6 unconditionally ---
    $host = trim($host, '[]');
    if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
        return false;
    }

    // --- 6. Resolve hostname to an IPv4 address ---
    if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
        // Supplied directly as an IPv4 literal
        $resolved_ip = $host;
    } else {
        $resolved_ip = gethostbyname($host);
        // gethostbyname() returns the original string when resolution fails
        if ($resolved_ip === $host) {
            return false;
        }
        // Sanity: result must be a valid IPv4 (not IPv6 returned by some stacks)
        if (filter_var($resolved_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) {
            return false;
        }
    }

    // --- 7. filter_var blocks loopback, private (A/B/C), and reserved ranges ---
    if (filter_var($resolved_ip,
                   FILTER_VALIDATE_IP,
                   FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
        return false;
    }

    // --- 8. Extra ranges not fully covered by filter_var flags ---
    $ip_long = ip2long($resolved_ip);
    $extra_blocked = array(
        // link-local / AWS & GCP metadata (169.254.0.0/16)
        array(ip2long('169.254.0.0'), ip2long('169.254.255.255')),
        // shared address space (100.64.0.0/10, RFC 6598)
        array(ip2long('100.64.0.0'),  ip2long('100.127.255.255')),
        // 0.0.0.0/8 — "this" network, resolves to localhost on some OS
        array(ip2long('0.0.0.0'),     ip2long('0.255.255.255')),
        // 240.0.0.0/4 — reserved future use
        array(ip2long('240.0.0.0'),   ip2long('255.255.255.254')),
    );

    foreach ($extra_blocked as $range) {
        if ($ip_long !== false && $ip_long >= $range[0] && $ip_long <= $range[1]) {
            return false;
        }
    }

    return true;
}

function Run_HTTP_scan()
{
    $links = $_POST['links'];
    $ssl_check_code = $_POST['ssl_check_code'];
    
    if (function_exists('openssl_private_decrypt'))
    {
        $key = '-----BEGIN PRIVATE KEY-----
MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEA5VRNEHvvuvVIzlQU
3wXzF/OoKf+SplcM5t2oUwSXnP+TdRmoRq6rhvjfgvc2ruZAkBYI1yrOhmL57xkE
dIKS+wIDAQABAkAeW/6nxACEm5w71F2++Kap8RO+G5tqcfO/THDQLLd1jQ/W9hy2
PpfQvYRCj5EydC5mSVTCgZJ+eB9L839tI2fhAiEA/zX3+kXUGALD/rX7i9Jn5rwI
BwCYgKBwiEghtmJLWOUCIQDmCdgKaGI/B2m5ftq+v4lNXNsMOrUXuQUKQjTu7D7e
XwIhAIGD9vvI8jDZPnQGEMlNlzMOW5iKIdqtEU7oJEu1qH1NAiEA0vt8Vi9ezIg0
A5nBbumlOHtNvG2r4lIjuUD345pyHukCIQCZ1XMZh+GK8eKDgIHpzhiQGK274BIx
55aH+nl8lg5t0w==
-----END PRIVATE KEY-----';

    	$ssl_check_code = base64_decode($ssl_check_code);
    	openssl_private_decrypt($ssl_check_code, $result, $key);
    	if ( trim($result) != date("Y-m-d")) return json_encode(array());

        $a = array();
        $links = (array)json_decode($links, true);
        if (count($links))
        {
            foreach ($links as $k => $link)
            {
                if (!is_safe_url_for_http_scan($link)) {
                    $a[$k] = false;
                    continue;
                }
                // Redirects disabled: a redirect to an internal address would bypass
                // the URL validation performed above.
                $a[$k] = GetRemote_file_contents($link, array(), false, false);
            }
            
            return json_encode($a);
        }
    }
    else return json_encode(array());
}


function GetRemote_file_contents($url, $post_data = array(), $parse = false, $follow_redirects = true)
{
    $client = EasyRequest_AVP::create('POST', $url, array(
        'form_params'      => $post_data,
        'follow_redirects' => $follow_redirects ? 1 : 0,
    ));
    $client->send();
    $http_status = $client->getResponseStatus();
    $output = trim($client->getResponseBody());
    
    if ($http_status != 200)
    {
        return false;
    }
    
    if ($output == '')  return false;
    
    if ($parse === true) $output = (array)json_decode($output, true);
    
    return $output;
}



function CreateRemote_file_contents($url, $dst)
{
    $a = CreateRemote_file_contents_ext($url, $dst);
    
    if ($a === false || $a == 0) 
    {
        if (stripos($url, "http://") !== false)
        {
            $url = str_replace("http://", "https://", $url);
            $a = CreateRemote_file_contents_ext($url, $dst);
        }
    }
    
    return $a;
}

function CreateRemote_file_contents_ext($url, $dst)
{
    if (extension_loaded('curl')) 
    {
        $dst = fopen($dst, 'w');
        
        $ch = curl_init();
        
        curl_setopt($ch, CURLOPT_URL, $url );
        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:38.0) Gecko/20100101 Firefox/38.0");
        curl_setopt($ch, CURLOPT_TIMEOUT, 3600);
        curl_setopt($ch, CURLOPT_TIMEOUT_MS, 3600000);
        curl_setopt($ch, CURLOPT_FILE, $dst);
        curl_setopt($ch, CURLOPT_FAILONERROR, true);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); // 30 sec
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 30000); // 30 sec
        curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        
        $a = curl_exec($ch);
        if ($a === false)  return false;
        
        $info = curl_getinfo($ch);
        
        curl_close($ch);
        fflush($dst);
        fclose($dst);
        
        return $info['size_download'];
    }
    else return false;
}



function GetStatus()
{
	$a = array( 
		'answer' => md5(trim($_REQUEST['answer'])),
		'version' => SCRIPT_VERSION,
		'md5' => md5_file(__FILE__),
		'debug' => ReadDebug()
	);
	return $a;
} 


function PrintResultOutput($msg, $type = false) // false = error, true - ok
{
    if ($type)
    {
        // Success
        if (is_array($msg))
        {
        	$a = $msg;
			$a['status'] = 'ok';
        }
        else {
        	$a = array(
            	'status' => 'ok',
            	'msg' => $msg
        	);
       	}
    } 
    else {
        // Error
        if (is_array($msg))
        {
        	$a = $msg;
			$a['status'] = 'error';
        }
        else {
        	$a = array(
            	'status' => 'error',
            	'msg' => $msg
        	);
       	}
    }
    
    echo json_encode($a);
}




function GetLicenseInfo($domain, $access_key)
{
    $data = array(
		'domain' => $domain,
		'access_key' => $access_key,
		'product_type' => 'any',
        'version' => SCRIPT_VERSION,
	);
    
	$post = array(
		'action' => 'licenseinfo',
		'type' => 'json',
        'data' => base64_encode(json_encode($data)),
	);
    
    $client = EasyRequest_AVP::create('POST', SITEGUARDING_SERVER, array(
        'form_params' => $post
    ));
    $client->send();
    $http_status = $client->getResponseStatus();
    $msg = trim($client->getResponseBody());
    
    if ($http_status != 200)
    {
        return false;
    }

    
    if ($msg == '' || $msg === false) return false;
    
    $license_data = (array)json_decode($msg, true);
    
    if (count($license_data) == 0) return false;
    
    // Check for new version & Auto update
    if ($license_data['latest_version'] > SCRIPT_VERSION)
    {
        // Do update
        $tmp_file = __FILE__.'.tmp';
        CreateRemote_file_contents($license_data['latest_version'], $tmp_file);
        if (md5($tmp_file) == $license_data['md5'])
        {
            unlink(__FILE__);
            copy($tmp_file, __FILE__);
            unlink($tmp_file);
        }
    }
    
    return $license_data;
}


function GetUpdateInfo($domain, $access_key, $version = '')
{
    $data = array(
		'domain' => $domain,
		'access_key' => $access_key,
        'version' => $version,
		'product_type' => 'any'
	);
    
	$post = array(
		'action' => 'updateinfo',
        'data' => base64_encode(json_encode($data)),
	);
    
    $client = EasyRequest_AVP::create('POST', SITEGUARDING_SERVER, array(
        'form_params' => $post
    ));
    $client->send();
    $http_status = $client->getResponseStatus();
    $msg = trim($client->getResponseBody());
    
    if ($http_status != 200)
    {
        return false;
    }
    
    
    if ($msg == '' || $msg === false) return false;
    
    return (array)json_decode($msg, true);
}
	


function get_malware_files()
{
	error_reporting(0);

	$domain = GetDomain();
			
	$license_info = GetLicenseInfo($domain, ACCESS_KEY);


	if (intval($_GET['showcontent']) == 1)
	{
		SendFilesForAnalyze( $license_info['last_scan_files'], $license_info['email'], true );
		exit;
	}
	

	$a = SendFilesForAnalyze( $license_info['last_scan_files'], $license_info['email'] );
	if ($a === true)
	{
		$tmp_txt = 'Files sent for analyze. You will get report by email '.$license_info['email'].' Files:'.print_r( $license_info['last_scan_files'],true);
		
		$result_txt = array(
			'status' => 'OK',
			'description' => $tmp_txt
		);
		//SGAntiVirus_scanner::DebugLog($tmp_txt);
	}
	else {
		$tmp_txt = 'Operation is failed. Nothing sent for analyze. Files:'.print_r( $license_info['last_scan_files'],true);
		
		$result_txt = array(
			'status' => 'ERROR',
			'description' => $tmp_txt
		);
		//SGAntiVirus_scanner::DebugLog($tmp_txt);
	}
	
	return json_encode($result_txt);
}


function SendFilesForAnalyze($files_array = array(), $email_from = '', $show_output = false)
{
    $domain = GetDomain();

	if (trim($email_from) == '') $email_from = 'dontreply@siteguarding.com';

	$result = false;
	$files = array();
	
	if (count($files_array['main']))
	{
		foreach ($files_array['main'] as $k => $filename)
		{
			$files[$filename] = $filename;	
		}
	}
	if (count($files_array['heuristic']))
	{
		foreach ($files_array['heuristic'] as $k => $filename)
		{
			$files[$filename] = $filename;	
		}
	}
	sort($files);
	
	
	if (count($files))
	{
        // Zip files
        $zip_file = 'check_'.md5(__FILE__).'.zip';
        $zip_file_url = $domain.'/webanalyze/'.$zip_file;
            //SGAntiVirus_scanner::DebugLog('Files for analyze (url): '.$zip_file_url);
        $zip_file = dirname(__FILE__).DIRSEP.$zip_file;
            //SGAntiVirus_scanner::DebugLog('Files for analyze: '.$zip_file);
        $status = ZipFilesList($zip_file, $files);
        if ($status === false) return false;
        
		$md5_list = array();
		
		$attachments = $files;
		$message_files = '';
		foreach ($attachments as $k => $v)
		{
			$attachments[$k] = dirname(__FILE__).DIRSEP.$v;
			$message_files .= $v."<br>";
			$md5_list[] = array(
				'File' => $v,
				'md5' => strtoupper(md5_file(dirname(__FILE__).'/'.$v))
			);
		}

		// To send HTML mail, the Content-type header must be set
		$headers  = 'MIME-Version: 1.0' . "\r\n";
		$headers .= 'Content-type: text/html; charset=UTF-8' . "\r\n";
		
		// Additional headers
		$headers .= "From: ".$domain." <".$email_from.">" . "\r\n";
		
		// Mail it
		$mailto = 'review@siteguarding.com';
		$subject = 'Antivirus Files Review ('.$domain.')';
		$body_message = 'Files for review. Domain: '.$domain."<br>";
		$body_message .= 'Platform: '.ANTIVIRUS_PLATFORM."<br>";
		$body_message .= 'Zip URL: '.$zip_file_url."<br>";
		$body_message .= 'Antivirus Version: '.SCRIPT_VERSION."<br>";
		$body_message .= "<br><br>Files:<br><br>".$message_files;
		$body_message .= "<br><br>MD5:<br><pre>".print_r($md5_list, true)."</pre>";

		if ($show_output === true) 
		{
            // Show message
			echo $body_message;
            return true;
		}
        else {
            // Send email
    		$result = mail($mailto, $subject, $body_message, $headers);
        }
	}
	
	return $result;
}



function ZipFilesList($zip_filename, $files_list)
{
    if (file_exists($zip_filename)) unlink($zip_filename);
    
    if (count($files_list) == 0) return false;

    $scan_path = SCAN_PATH;
    
    $zip = new ZipSGAVP();
    $zip->setZipFile($zip_filename);
    foreach ($files_list as $file_name_short) 
    {
    	$file_name = trim($scan_path.$file_name_short);
        
    	$handle = @fopen($file_name, "rb");
    	if ($handle === false) continue;
    	$fsize = filesize($file_name);
    	if ($fsize > 0)
    	{
    		$data = fread($handle, $fsize);
    		if ($data !== false) $zip->addFile($data, $file_name_short, filectime($file_name), NULL, TRUE, ZipSGAVP::getFileExtAttr($file_name));
    	}
    	fclose($handle);
    }
    $zip->finalize();
   
    return true;
}



function ReadDebug()
{
	// Read debug file
	$filename = dirname(__FILE__).DIRSEP.'debug_'.md5(ACCESS_KEY).'.log';
    if (!file_exists($filename)) return '';
	$handle = fopen($filename, "r");
	if ($handle === false) return '';
	$contents = fread($handle, filesize($filename));
	fclose($handle);
	
	return $contents;
}



/**
 * Extra classes
 */

class ZipSGAVP {
    const VERSION = 1.62;

    const ZIP_LOCAL_FILE_HEADER = "\x50\x4b\x03\x04";
    const ZIP_CENTRAL_FILE_HEADER = "\x50\x4b\x01\x02";
    const ZIP_END_OF_CENTRAL_DIRECTORY = "\x50\x4b\x05\x06\x00\x00\x00\x00";

    const EXT_FILE_ATTR_DIR = 010173200020;
    const EXT_FILE_ATTR_FILE = 020151000040;

    const ATTR_VERSION_TO_EXTRACT = "\x14\x00";
    const ATTR_MADE_BY_VERSION = "\x1E\x03";

	const EXTRA_FIELD_NEW_UNIX_GUID = "\x75\x78\x0B\x00\x01\x04\xE8\x03\x00\x00\x04\x00\x00\x00\x00";

	const S_IFIFO  = 0010000;
	const S_IFCHR  = 0020000; // character special
	const S_IFDIR  = 0040000; // directory
	const S_IFBLK  = 0060000; // block special
	const S_IFREG  = 0100000; // regular
	const S_IFLNK  = 0120000; // symbolic link
	const S_IFSOCK = 0140000; // socket

	const S_ISUID  = 0004000; 
	const S_ISGID  = 0002000; 
	const S_ISTXT  = 0001000; // sticky bit

	const S_IRWXU  = 0000700; 
	const S_IRUSR  = 0000400; 
	const S_IWUSR  = 0000200; 
	const S_IXUSR  = 0000100; // X for owner
	const S_IRWXG  = 0000070; 
	const S_IRGRP  = 0000040; // R for group
	const S_IWGRP  = 0000020; // W for group
	const S_IXGRP  = 0000010; // X for group
	const S_IRWXO  = 0000007; // RWX mask for other
	const S_IROTH  = 0000004; // R for other
	const S_IWOTH  = 0000002; 
	const S_IXOTH  = 0000001; 
	const S_ISVTX  = 0001000; 

	const S_DOS_A  = 0000040; 
	const S_DOS_D  = 0000020; 
	const S_DOS_V  = 0000010; 
	const S_DOS_S  = 0000004; 
	const S_DOS_H  = 0000002; 
	const S_DOS_R  = 0000001; 

    private $zipMemoryThreshold = 1048576; 

    private $zipData = NULL;
    private $zipFile = NULL;
    private $zipComment = NULL;
    private $cdRec = array(); 
    private $offset = 0;
    private $isFinalized = FALSE;
    private $addExtraField = TRUE;

    private $streamChunkSize = 65536;
    private $streamFilePath = NULL;
    private $streamTimestamp = NULL;
    private $streamFileComment = NULL;
    private $streamFile = NULL;
    private $streamData = NULL;
    private $streamFileLength = 0;
	private $streamExtFileAttr = null;

	public static $temp = null;


    function __construct($useZipFile = FALSE) {
        if ($useZipFile) {
            $this->zipFile = tmpfile();
        } else {
            $this->zipData = "";
        }
    }

    function __destruct() {
        if (is_resource($this->zipFile)) {
            fclose($this->zipFile);
        }
        $this->zipData = NULL;
    }

    function setExtraField($setExtraField = TRUE) {
        $this->addExtraField = ($setExtraField === TRUE);
    }


    public function setComment($newComment = NULL) {
        if ($this->isFinalized) {
            return FALSE;
        }
        $this->zipComment = $newComment;

        return TRUE;
    }

    public function setZipFile($fileName) {
        if (is_file($fileName)) {
            unlink($fileName);
        }
        $fd=fopen($fileName, "x+b");
        if (is_resource($this->zipFile)) {
            rewind($this->zipFile);
            while (!feof($this->zipFile)) {
                fwrite($fd, fread($this->zipFile, $this->streamChunkSize));
            }

            fclose($this->zipFile);
        } else {
            fwrite($fd, $this->zipData);
            $this->zipData = NULL;
        }
        $this->zipFile = $fd;

        return TRUE;
    }


    public function addDirectory($directoryPath, $timestamp = 0, $fileComment = NULL, $extFileAttr = self::EXT_FILE_ATTR_DIR) {
        if ($this->isFinalized) {
            return FALSE;
        }
        $directoryPath = str_replace("\\", "/", $directoryPath);
        $directoryPath = rtrim($directoryPath, "/");

        if (strlen($directoryPath) > 0) {
            $this->buildZipEntry($directoryPath.'/', $fileComment, "\x00\x00", "\x00\x00", $timestamp, "\x00\x00\x00\x00", 0, 0, $extFileAttr);
            return TRUE;
        }
        return FALSE;
    }


    public function addFile($data, $filePath, $timestamp = 0, $fileComment = NULL, $compress = TRUE, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
        if ($this->isFinalized) {
            return FALSE;
        }

        if (is_resource($data) && get_resource_type($data) == "stream") {
            $this->addLargeFile($data, $filePath, $timestamp, $fileComment, $extFileAttr);
            return FALSE;
        }

        $gzData = "";
        $gzType = "\x08\x00"; 
        $gpFlags = "\x00\x00"; 
        $dataLength = strlen($data);
        $fileCRC32 = pack("V", crc32($data));

        if ($compress) {
            $gzTmp = gzcompress($data);
            $gzData = substr(substr($gzTmp, 0, strlen($gzTmp) - 4), 2); 
            
            $gzLength = strlen($gzData);
        } else {
            $gzLength = $dataLength;
        }

        if ($gzLength >= $dataLength) {
            $gzLength = $dataLength;
            $gzData = $data;
            $gzType = "\x00\x00"; 
            $gpFlags = "\x00\x00"; 
        }

        if (!is_resource($this->zipFile) && ($this->offset + $gzLength) > $this->zipMemoryThreshold) {
            $this->zipflush();
        }

        $this->buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr);

        $this->zipwrite($gzData);

        return TRUE;
    }


    public function addDirectoryContent($realPath, $zipPath, $recursive = TRUE, $followSymlinks = TRUE, &$addedFiles = array(),
					$overrideFilePermissions = FALSE, $extDirAttr = self::EXT_FILE_ATTR_DIR, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
        if (file_exists($realPath) && !isset($addedFiles[realpath($realPath)])) {
            if (is_dir($realPath)) {
				if ($overrideFilePermissions) {
	                $this->addDirectory($zipPath, 0, null, $extDirAttr);
				} else {
					$this->addDirectory($zipPath, 0, null, self::getFileExtAttr($realPath));
				}
            }

            $addedFiles[realpath($realPath)] = $zipPath;

            $iter = new DirectoryIterator($realPath);
            foreach ($iter as $file) {
                if ($file->isDot()) {
                    continue;
                }
                $newRealPath = $file->getPathname();
                $newZipPath = self::pathJoin($zipPath, $file->getFilename());

                if (file_exists($newRealPath) && ($followSymlinks === TRUE || !is_link($newRealPath))) {
                    if ($file->isFile()) {
                        $addedFiles[realpath($newRealPath)] = $newZipPath;
						if ($overrideFilePermissions) {
							$this->addLargeFile($newRealPath, $newZipPath, 0, null, $extFileAttr);
						} else {
							$this->addLargeFile($newRealPath, $newZipPath, 0, null, self::getFileExtAttr($newRealPath));
						}
                    } else if ($recursive === TRUE) {
                        $this->addDirectoryContent($newRealPath, $newZipPath, $recursive, $followSymlinks, $addedFiles, $overrideFilePermissions, $extDirAttr, $extFileAttr);
                    } else {
						if ($overrideFilePermissions) {
							$this->addDirectory($zipPath, 0, null, $extDirAttr);
						} else {
							$this->addDirectory($zipPath, 0, null, self::getFileExtAttr($newRealPath));
						}
                    }
                }
            }
        }
    }


    public function addLargeFile($dataFile, $filePath, $timestamp = 0, $fileComment = NULL, $extFileAttr = self::EXT_FILE_ATTR_FILE)   {
        if ($this->isFinalized) {
            return FALSE;
        }

        if (is_string($dataFile) && is_file($dataFile)) {
            $this->processFile($dataFile, $filePath, $timestamp, $fileComment, $extFileAttr);
        } else if (is_resource($dataFile) && get_resource_type($dataFile) == "stream") {
            $fh = $dataFile;
            $this->openStream($filePath, $timestamp, $fileComment, $extFileAttr);

            while (!feof($fh)) {
                $this->addStreamData(fread($fh, $this->streamChunkSize));
            }
            $this->closeStream($this->addExtraField);
        }
        return TRUE;
    }


    public function openStream($filePath, $timestamp = 0, $fileComment = null, $extFileAttr = self::EXT_FILE_ATTR_FILE)   {
        if (!function_exists('sys_get_temp_dir')) {
            throw new Exception("Zip " . self::VERSION . " requires PHP version 5.2.1 or above if large files are used.");
        }

        if ($this->isFinalized) {
            return FALSE;
        }

        $this->zipflush();

        if (strlen($this->streamFilePath) > 0) {
            $this->closeStream();
        }

        $this->streamFile = self::getTemporaryFile();
        $this->streamData = fopen($this->streamFile, "wb");
        $this->streamFilePath = $filePath;
        $this->streamTimestamp = $timestamp;
        $this->streamFileComment = $fileComment;
        $this->streamFileLength = 0;
		$this->streamExtFileAttr = $extFileAttr;

        return TRUE;
    }


    public function addStreamData($data) {
        if ($this->isFinalized || strlen($this->streamFilePath) == 0) {
            return FALSE;
        }

        $length = fwrite($this->streamData, $data, strlen($data));
        if ($length != strlen($data)) {
			throw new Exception("File IO: Error writing; Length mismatch: Expected " . strlen($data) . " bytes, wrote " . ($length === FALSE ? "NONE!" : $length));
		}
		$this->streamFileLength += $length;
        
		return $length;
    }


    public function closeStream() {
        if ($this->isFinalized || strlen($this->streamFilePath) == 0) {
            return FALSE;
        }

        fflush($this->streamData);
        fclose($this->streamData);

        $this->processFile($this->streamFile, $this->streamFilePath, $this->streamTimestamp, $this->streamFileComment, $this->streamExtFileAttr);

        $this->streamData = null;
        $this->streamFilePath = null;
        $this->streamTimestamp = null;
        $this->streamFileComment = null;
        $this->streamFileLength = 0;
		$this->streamExtFileAttr = null;


        unlink($this->streamFile);

        $this->streamFile = null;

        return TRUE;
    }

    private function processFile($dataFile, $filePath, $timestamp = 0, $fileComment = null, $extFileAttr = self::EXT_FILE_ATTR_FILE) {
        if ($this->isFinalized) {
            return FALSE;
        }

        $tempzip = self::getTemporaryFile();

        $zip = new ZipArchive;
        if ($zip->open($tempzip) === TRUE) {
            $zip->addFile($dataFile, 'file');
            $zip->close();
        }

        $file_handle = fopen($tempzip, "rb");
        $stats = fstat($file_handle);
        $eof = $stats['size']-72;

        fseek($file_handle, 6);

        $gpFlags = fread($file_handle, 2);
        $gzType = fread($file_handle, 2);
        fread($file_handle, 4);
        $fileCRC32 = fread($file_handle, 4);
        $v = unpack("Vval", fread($file_handle, 4));
        $gzLength = $v['val'];
        $v = unpack("Vval", fread($file_handle, 4));
        $dataLength = $v['val'];

        $this->buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr);

        fseek($file_handle, 34);
        $pos = 34;

        while (!feof($file_handle) && $pos < $eof) {
            $datalen = $this->streamChunkSize;
            if ($pos + $this->streamChunkSize > $eof) {
                $datalen = $eof-$pos;
            }
            $data = fread($file_handle, $datalen);
            $pos += $datalen;

            $this->zipwrite($data);
        }

        fclose($file_handle);

        unlink($tempzip);
    }


    public function finalize() {
        if (!$this->isFinalized) {
            if (strlen($this->streamFilePath) > 0) {
                $this->closeStream();
            }
            $cd = implode("", $this->cdRec);

            $cdRecSize = pack("v", sizeof($this->cdRec));
            $cdRec = $cd . self::ZIP_END_OF_CENTRAL_DIRECTORY
            . $cdRecSize . $cdRecSize
            . pack("VV", strlen($cd), $this->offset);
            if (!empty($this->zipComment)) {
                $cdRec .= pack("v", strlen($this->zipComment)) . $this->zipComment;
            } else {
                $cdRec .= "\x00\x00";
            }

            $this->zipwrite($cdRec);

            $this->isFinalized = TRUE;
            $this->cdRec = NULL;

            return TRUE;
        }
        return FALSE;
    }


    public function getZipFile() {
        if (!$this->isFinalized) {
            $this->finalize();
        }

        $this->zipflush();

        rewind($this->zipFile);

        return $this->zipFile;
    }


    public function getZipData() {
        if (!$this->isFinalized) {
            $this->finalize();
        }
        if (!is_resource($this->zipFile)) {
            return $this->zipData;
        } else {
            rewind($this->zipFile);
            $filestat = fstat($this->zipFile);
            return fread($this->zipFile, $filestat['size']);
        }
    }


	function sendZip($fileName = null, $contentType = "application/zip", $utf8FileName = null, $inline = false) {
		if (!$this->isFinalized) {
			$this->finalize();
		}
		$headerFile = null;
		$headerLine = null;
		if(headers_sent($headerFile, $headerLine)) {
        	throw new Exception("Unable to send file '$fileName'. Headers have already been sent from '$headerFile' in line $headerLine");
		}
		if(ob_get_contents() !== false && strlen(ob_get_contents())) {
			throw new Exception("Unable to send file '$fileName'. Output buffer contains the following text (typically warnings or errors):\n" . ob_get_contents());
		}
		if(@ini_get('zlib.output_compression')) {
			@ini_set('zlib.output_compression', 'Off');
		}
		header("Pragma: public");
		header("Last-Modified: " . @gmdate("D, d M Y H:i:s T"));
		header("Expires: 0");
		header("Accept-Ranges: bytes");
		header("Connection: close");
		header("Content-Type: " . $contentType);
		$cd = "Content-Disposition: ";
		if ($inline) {
			$cd .= "inline";
		} else {
			$cd .= "attached";
		}
		if ($fileName) {
			$cd .= '; filename="' . $fileName . '"';
		}
		if ($utf8FileName) {
			$cd .= "; filename*=UTF-8''" . rawurlencode($utf8FileName);
		}
		header($cd);
		header("Content-Length: ". $this->getArchiveSize());
		if (!is_resource($this->zipFile)) {
			echo $this->zipData;
		} else {
			rewind($this->zipFile);
			while (!feof($this->zipFile)) {
				echo fread($this->zipFile, $this->streamChunkSize);
			}
		}
		return true;
	}


    public function getArchiveSize() {
        if (!is_resource($this->zipFile)) {
            return strlen($this->zipData);
        }
        $filestat = fstat($this->zipFile);

        return $filestat['size'];
    }


    private function getDosTime($timestamp = 0) {
        $timestamp = (int)$timestamp;
        $oldTZ = @date_default_timezone_get();
        date_default_timezone_set('UTC');
        $date = ($timestamp == 0 ? getdate() : getdate($timestamp));
        date_default_timezone_set($oldTZ);
        if ($date["year"] >= 1980) {
            return pack("V", (($date["mday"] + ($date["mon"] << 5) + (($date["year"]-1980) << 9)) << 16) |
                    (($date["seconds"] >> 1) + ($date["minutes"] << 5) + ($date["hours"] << 11)));
        }
        return "\x00\x00\x00\x00";
    }

	private function is_utf8($string) {   
		return preg_match('%^(?:  
		[\x09\x0A\x0D\x20-\x7E] # ASCII  
		| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte  
		| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs  
		| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte  
		| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates  
		| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3  
		| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15  
		| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16  
		)*$%xs', $string);   
	}


    private function buildZipEntry($filePath, $fileComment, $gpFlags, $gzType, $timestamp, $fileCRC32, $gzLength, $dataLength, $extFileAttr) {
        $filePath = str_replace("\\", "/", $filePath);
        $fileCommentLength = (empty($fileComment) ? 0 : strlen($fileComment));
        $timestamp = (int)$timestamp;
        $timestamp = ($timestamp == 0 ? time() : $timestamp);

        $dosTime = $this->getDosTime($timestamp);
        $tsPack = pack("V", $timestamp);

        if (!isset($gpFlags) || strlen($gpFlags) != 2) {
            $gpFlags = "\x00\x00";
        }

        $isFileUTF8 = $this->is_utf8(file_get_contents($filePath));
        $isCommentUTF8 = !empty($fileComment) && $this->is_utf8($fileComment);
		
		$localExtraField = "";
		$centralExtraField = "";
		
		if ($this->addExtraField) {
            $localExtraField .= "\x55\x54\x09\x00\x03" . $tsPack . $tsPack . ZipSGAVP::EXTRA_FIELD_NEW_UNIX_GUID;
			$centralExtraField .= "\x55\x54\x05\x00\x03" . $tsPack . ZipSGAVP::EXTRA_FIELD_NEW_UNIX_GUID;
		}
		
		if ($isFileUTF8 || $isCommentUTF8) {
            $flag = 0;
            $gpFlagsV = unpack("vflags", $gpFlags);
            if (isset($gpFlagsV['flags'])) {
                $flag = $gpFlagsV['flags'];
            }
            $gpFlags = pack("v", $flag | (1 << 11));
			
			if ($isFileUTF8) {
				$utfPathExtraField = "\x75\x70"
					. pack ("v", (5 + strlen($filePath)))
					. "\x01" 
					.  pack("V", crc32($filePath))
					. $filePath;

				$localExtraField .= $utfPathExtraField;
				$centralExtraField .= $utfPathExtraField;
			}
			if ($isCommentUTF8) {
				$centralExtraField .= "\x75\x63" 
					. pack ("v", (5 + strlen($fileComment)))
					. "\x01"
					. pack("V", crc32($fileComment))
					. $fileComment;
			}
        }

        $header = $gpFlags . $gzType . $dosTime. $fileCRC32
			. pack("VVv", $gzLength, $dataLength, strlen($filePath));

        $zipEntry  = self::ZIP_LOCAL_FILE_HEADER
			. self::ATTR_VERSION_TO_EXTRACT
			. $header
			. pack("v", strlen($localExtraField))
			. $filePath // FileName
			. $localExtraField; // Extra fields

		$this->zipwrite($zipEntry);

        $cdEntry  = self::ZIP_CENTRAL_FILE_HEADER
			. self::ATTR_MADE_BY_VERSION
			. ($dataLength === 0 ? "\x0A\x00" : self::ATTR_VERSION_TO_EXTRACT)
			. $header
			. pack("v", strlen($centralExtraField))
			. pack("v", $fileCommentLength) 
			. "\x00\x00" 
			. "\x00\x00" 
			. pack("V", $extFileAttr) 
			. pack("V", $this->offset) 
			. $filePath 
			. $centralExtraField; 

		if (!empty($fileComment)) {
            $cdEntry .= $fileComment;
        }

        $this->cdRec[] = $cdEntry;
        $this->offset += strlen($zipEntry) + $gzLength;
    }

    private function zipwrite($data) {
        if (!is_resource($this->zipFile)) {
            $this->zipData .= $data;
        } else {
            fwrite($this->zipFile, $data);
            fflush($this->zipFile);
        }
    }

    private function zipflush() {
        if (!is_resource($this->zipFile)) {
            $this->zipFile = tmpfile();
            fwrite($this->zipFile, $this->zipData);
            $this->zipData = NULL;
        }
    }


    public static function pathJoin($dir, $file) {
        if (empty($dir) || empty($file)) {
            return self::getRelativePath($dir . $file);
        }
        return self::getRelativePath($dir . '/' . $file);
    }


    public static function getRelativePath($path) {
        $path = preg_replace("#/+\.?/+#", "/", str_replace("\\", "/", $path));
        $dirs = explode("/", rtrim(preg_replace('#^(?:\./)+#', '', $path), '/'));

        $offset = 0;
        $sub = 0;
        $subOffset = 0;
        $root = "";

        if (empty($dirs[0])) {
            $root = "/";
            $dirs = array_splice($dirs, 1);
        } else if (preg_match("#[A-Za-z]:#", $dirs[0])) {
            $root = strtoupper($dirs[0]) . "/";
            $dirs = array_splice($dirs, 1);
        }

        $newDirs = array();
        foreach ($dirs as $dir) {
            if ($dir !== "..") {
                $subOffset--;
                $newDirs[++$offset] = $dir;
            } else {
                $subOffset++;
                if (--$offset < 0) {
                    $offset = 0;
                    if ($subOffset > $sub) {
                        $sub++;
                    }
                }
            }
        }

        if (empty($root)) {
            $root = str_repeat("../", $sub);
        }
        return $root . implode("/", array_slice($newDirs, 0, $offset));
    }


	public static function generateExtAttr($owner = 07, $group = 05, $other = 05, $isFile = true) {
		$fp = $isFile ? self::S_IFREG : self::S_IFDIR;
		$fp |= (($owner & 07) << 6) | (($group & 07) << 3) | ($other & 07);

		return ($fp << 16) | ($isFile ? self::S_DOS_A : self::S_DOS_D);
	}


	public static function getFileExtAttr($filename) {
		if (file_exists($filename)) {
			$fp = fileperms($filename) << 16;
			return $fp | (is_dir($filename) ? self::S_DOS_D : self::S_DOS_A);
		}
		return FALSE;
	}

	private static function getTemporaryFile() {
		if(is_callable(self::$temp)) {
			$temporaryFile = @call_user_func(self::$temp);
			if(is_string($temporaryFile) && strlen($temporaryFile) && is_writable($temporaryFile)) {
				return $temporaryFile;
			}
		}
		$temporaryDirectory = (is_string(self::$temp) && strlen(self::$temp)) ? self::$temp : sys_get_temp_dir();
		return tempnam($temporaryDirectory, 'Zip');
	}
}



class SGAntiVirus_SQL_scanner
{
	/**
	 * Opens a mysqli connection in a way that works across PHP 5.6 - 8.x.
	 *
	 *  - Disables mysqli's exception mode (PHP 8.1+ throws by default, which the
	 *    old "if (!$conn)" checks did not catch -> fatal error). With it off,
	 *    a failed connection returns false as the callers expect.
	 *  - Parses the host string into host / port / socket so values like
	 *    "127.0.0.1:3306" or "localhost:/var/run/mysqld/mysqld.sock" connect
	 *    correctly instead of being passed verbatim as the hostname.
	 *  - Applies a connect timeout so an unreachable DB cannot hang the scan.
	 *
	 * @return mysqli|false
	 */
	static public function SafeConnect($server, $user, $pass, $database)
	{
		if (function_exists('mysqli_report'))
		{
			// MYSQLI_REPORT_OFF exists since PHP 5.3; keep behaviour = return false on error.
			mysqli_report(MYSQLI_REPORT_OFF);
		}
		
		$host   = $server;
		$port   = null;
		$socket = null;
		
		// Split "host:port" or "host:/path/to/socket"
		if (is_string($server) && strpos($server, ':') !== false)
		{
			list($host, $tail) = explode(':', $server, 2);
			$tail = trim($tail);
			if ($tail !== '')
			{
				if (preg_match('/^\d+$/', $tail)) $port = (int)$tail;   // numeric -> TCP port
				else                              $socket = $tail;      // otherwise -> unix socket path
			}
		}
		if ($host === '') $host = null;
		
		$conn = @mysqli_init();
		if ($conn === false) return false;
		
		// 10s connect timeout (best effort - ignored if the option is unsupported).
		@mysqli_options($conn, MYSQLI_OPT_CONNECT_TIMEOUT, 10);
		
		$ok = @mysqli_real_connect($conn, $host, $user, $pass, $database, $port, $socket);
		if ($ok === false) return false;
		
		return $conn;
	}
	
	/**
	 * Parses a wp-config.php WITHOUT executing it, using the tokenizer.
	 * Extracts the DB_* constants and $table_prefix when their value is a plain
	 * string literal. Non-literal values (getenv(), concatenation, etc.) are
	 * skipped rather than guessed, and nothing is eval()'d or defined globally.
	 *
	 * @return array keys: DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, table_prefix (null when not found)
	 */
	static public function ParseWordPressConfig($config_file)
	{
		$out = array(
			'DB_NAME'      => null,
			'DB_USER'      => null,
			'DB_PASSWORD'  => null,
			'DB_HOST'      => null,
			'table_prefix' => null,
		);
		
		if (!function_exists('token_get_all')) return $out;   // tokenizer extension missing
		
		$src = @file_get_contents($config_file);
		if ($src === false || $src === '') return $out;
		
		$tokens = @token_get_all($src);
		if (!is_array($tokens)) return $out;
		
		// Compact to significant tokens only: array(id, text); punctuation gets id -1.
		$sig = array();
		foreach ($tokens as $t)
		{
			if (is_array($t))
			{
				if ($t[0] === T_WHITESPACE || $t[0] === T_COMMENT
					|| (defined('T_DOC_COMMENT') && $t[0] === T_DOC_COMMENT)) continue;
				$sig[] = array($t[0], $t[1]);
			}
			else
			{
				$sig[] = array(-1, $t);
			}
		}
		
		$m = count($sig);
		for ($i = 0; $i < $m; $i++)
		{
			// define('NAME', 'value')  -> accept only a single string-literal value
			if ($sig[$i][0] === T_STRING && strcasecmp($sig[$i][1], 'define') === 0
				&& isset($sig[$i + 5])
				&& $sig[$i + 1][0] === -1 && $sig[$i + 1][1] === '('
				&& $sig[$i + 2][0] === T_CONSTANT_ENCAPSED_STRING
				&& $sig[$i + 3][0] === -1 && $sig[$i + 3][1] === ','
				&& $sig[$i + 4][0] === T_CONSTANT_ENCAPSED_STRING
				&& $sig[$i + 5][0] === -1 && $sig[$i + 5][1] === ')')
			{
				$name = self::UnquotePhpString($sig[$i + 2][1]);
				if (array_key_exists($name, $out))
				{
					$out[$name] = self::UnquotePhpString($sig[$i + 4][1]);
				}
			}
			
			// $table_prefix = 'value';
			if ($sig[$i][0] === T_VARIABLE && $sig[$i][1] === '$table_prefix'
				&& isset($sig[$i + 3])
				&& $sig[$i + 1][0] === -1 && $sig[$i + 1][1] === '='
				&& $sig[$i + 2][0] === T_CONSTANT_ENCAPSED_STRING
				&& $sig[$i + 3][0] === -1 && $sig[$i + 3][1] === ';')
			{
				$out['table_prefix'] = self::UnquotePhpString($sig[$i + 2][1]);
			}
		}
		
		return $out;
	}
	
	/**
	 * Turns a PHP string literal token (with surrounding quotes) into its value,
	 * without eval. Handles the escapes that matter for credentials.
	 */
	static public function UnquotePhpString($literal)
	{
		$literal = trim($literal);
		if (strlen($literal) < 2) return $literal;
		
		$q = $literal[0];
		if ($q !== '"' && $q !== "'") return $literal;
		
		$inner = substr($literal, 1, -1);
		
		if ($q === "'")
		{
			// single-quoted: only \\ and \' are escapes
			return preg_replace_callback('/\\\\([\\\\\'])/', function($mm){ return $mm[1]; }, $inner);
		}
		// double-quoted: handle \\ \" \$ (other interpolation is not resolved)
		return preg_replace_callback('/\\\\([\\\\"$])/', function($mm){ return $mm[1]; }, $inner);
	}
	
	static public function DetectCMS()
	{
        if ( (file_exists(SCAN_PATH.'wp-config.php') || file_exists(dirname(SCAN_PATH).DIRSEP.'wp-config.php')) && file_exists(SCAN_PATH.'wp-includes'.DIRSEP.'version.php')) return 'wordpress';
        if (file_exists(SCAN_PATH.'configuration.php') && file_exists(SCAN_PATH.'administrator'.DIRSEP.'index.php')) return 'joomla';
        if (file_exists(SCAN_PATH.'app'.DIRSEP.'Mage.php') || file_exists(SCAN_PATH.'vendor'.DIRSEP.'magento'.DIRSEP.'magento2-base'.DIRSEP.'composer.json')) return 'magento';
        
        return 'other';
    }
    
	static public function GetSQLsettings($cms = '')
	{
        $a = array(
            'sql_server' => '',
            'sql_database' => '',
            'sql_username' => '',
            'sql_password' => '',
            'prefix' => ''
        );
        
        switch ($cms)
        {
            case 'wordpress':
                $config_file = SCAN_PATH.'wp-config.php';
                if (!file_exists($config_file)) $config_file = dirname(SCAN_PATH).DIRSEP.'wp-config.php';
                if (file_exists($config_file))
                {
                    $wp = self::ParseWordPressConfig($config_file);
                    if ($wp['DB_NAME']      !== null) $a['sql_database'] = $wp['DB_NAME'];
                    if ($wp['DB_USER']      !== null) $a['sql_username'] = $wp['DB_USER'];
                    if ($wp['DB_PASSWORD']  !== null) $a['sql_password'] = $wp['DB_PASSWORD'];
                    if ($wp['DB_HOST']      !== null) $a['sql_server']   = $wp['DB_HOST'];
                    if ($wp['table_prefix'] !== null) $a['prefix']       = $wp['table_prefix'];
                }
                break;
                
            case 'joomla':
                $config_file = SCAN_PATH.'configuration.php';
                if (file_exists($config_file))
                {
                    if (!class_exists('JConfig'))
                    {
                        include_once($config_file);
                    }
                    if (class_exists('JConfig'))
                    {
                        $db = new JConfig();
                        $a['sql_server'] = $db->host;
                        $a['sql_username'] = $db->user;
                        $a['sql_password'] = $db->password;
                        $a['sql_database'] = $db->db;
                        $a['prefix'] = $db->dbprefix;
                    }
                }
                break;
                
            case 'magento':
                // Magento 1 (app/etc/local.xml) - resolve path from SCAN_PATH, no die() on failure
                $mage1 = SCAN_PATH."app".DIRSEP."etc".DIRSEP."local.xml";
                if (file_exists($mage1) && function_exists('simplexml_load_file'))
                {
                    $xml = @simplexml_load_file($mage1);
                    if ($xml !== false && isset($xml->global->resources->default_setup->connection))
                    {
                        $conn = $xml->global->resources->default_setup->connection;
                        $a['sql_server']   = (string)$conn->host;
                        $a['sql_username'] = (string)$conn->username;
                        $a['sql_password'] = (string)$conn->password;
                        $a['sql_database'] = (string)$conn->dbname;
                        if (isset($xml->global->resources->db->table_prefix))
                            $a['prefix'] = (string)$xml->global->resources->db->table_prefix;
                    }
                }
                
                // Magento 2 (app/etc/env.php) - resolve path from SCAN_PATH, validate returned array
                $mage2 = SCAN_PATH."app".DIRSEP."etc".DIRSEP."env.php";
                if (file_exists($mage2))
                {
                    $data = @include($mage2);
                    if (is_array($data) && isset($data['db']['connection']['default']))
                    {
                        $def = $data['db']['connection']['default'];
                        if (isset($def['host']))     $a['sql_server']   = $def['host'];
                        if (isset($def['username'])) $a['sql_username'] = $def['username'];
                        if (isset($def['password'])) $a['sql_password'] = $def['password'];
                        if (isset($def['dbname']))   $a['sql_database'] = $def['dbname'];
                        if (isset($data['db']['table_prefix'])) $a['prefix'] = $data['db']['table_prefix'];
                    }
                }
                break;
                
            default: // other
        }
        
        return $a;
    }
    
	static public function ScanSQLContent($domain, $sql_settings = array(), $cms = '')
	{
        $a = array();
        
   	    if ($sql_settings['sql_username'] == '' || $sql_settings['sql_password'] == '' || $sql_settings['sql_database'] == '') return array('status' => false, 'reason' => 'Empty SQL settings '.print_r($sql_settings, true));;
        
        if (function_exists("mysqli_connect") === false)
        {
            $a = array('status' => false, 'reason' => "mysqli_connect is absent");
            return $a;
        }
			
        $i_connect = self::SafeConnect($sql_settings['sql_server'], $sql_settings['sql_username'], $sql_settings['sql_password'], $sql_settings['sql_database']);
        
        // Magento
        if ($i_connect) 
        {
            if ($cms == 'magento') 
            {
                $query = "SELECT config_id, value, path FROM ".$sql_settings['prefix']."core_config_data WHERE value LIKE '%script%' OR value LIKE '%src=%'";
                $result = self::SQL_query($i_connect, $query );
                if ($result === false)
                {
                    $a = array('status' => false, 'reason' => mysqli_error($i_connect));
                    return $a;
                }
                
                $regex = "/\<script(.*?)?\>(.|\\n)*?\<\/script\>/i";
                
        		while ($r = mysqli_fetch_array($result))
        		{
        		    $post_content = $r['value'];
        		    $path = $r['path'];
                    preg_match_all($regex, $post_content, $scripts);
                    
                    if (count($scripts[0]))
                    {
                        $a['results']['data'][$path] = $scripts[0];
                    }
                }
                
                $a['status'] = true;
                $a['results']['cms'] = $cms;
                
                return $a;
            }
        }
        else $a = array('status' => false, 'reason' => 'Cant connect to SQL '.print_r($sql_settings, true));
        
        
        // WordPress & Joomla
        if ($i_connect) 
        {
            if ($cms == 'wordpress') $query = "SELECT ID, post_content AS val_data FROM ".$sql_settings['prefix']."posts";
            if ($cms == 'joomla') $query = "SELECT ID, introtext AS val_data FROM ".$sql_settings['prefix']."content";

            $result = self::SQL_query($i_connect, $query );
            if ($result === false)
            {
                $a = array('status' => false, 'reason' => mysqli_error($i_connect));
                return $a;
            }

            $a['results']['TOTAL_JS'] = 0;
            $a['results']['SCRIPT'] = array();
            $a['results']['IFRAME'] = array();
            $a['results']['A'] = array();
            
    		while ($r = mysqli_fetch_array($result))
    		{
                $post_content = "<html><body>".$r['val_data']."</body></html>";
                
                $html = str_get_html($post_content);


                if ($html !== false)
                {
                    $tmp_a = array();
                    
                    // Tag A
                    foreach($html->find('a') as $e) 
                    {
                        $link = strtolower(trim($e->href));
                        if (strpos($link, $domain) !== false) continue;     // Skip own links
                        if (strpos($link, "mailto:") !== false) continue;
                        if (strpos($link, "callto:") !== false) continue;
                        if ( $link[0] == '?' ) continue;
                        if ( $link[0] != 'h' && $link[1] != 't' && $link[2] != 't' && $link[3] != 'p' && $link[0] != '/' && $link[1] != '/' ) continue;
                        
                        $a['results']['A'][$link] = strip_tags($e->outertext);
                    }
                    
                    
                    
                    // Tag IFRAME
                    foreach($html->find('iframe') as $e) 
                    {
                        $link = strtolower(trim($e->src));
                        if (strpos($link, $domain) !== false) continue;     // Skip own links
                        if ( $link[0] == '?' ) continue;
                        if ( $link[0] != 'h' && $link[1] != 't' && $link[2] != 't' && $link[3] != 'p' && $link[0] != '/' && $link[1] != '/' ) continue;
                        
                        $a['results']['IFRAME'][$link] = $link;
                    }
                    
                    
                    
                	// Tag SCRIPT
                	foreach($html->find('script') as $e)
                	{
                	    $a['results']['TOTAL_JS']++;
                        
                	    if (isset($e->src)) 
                        {
                            $link = strtolower(trim($e->src));
                        
                            if (strpos($link, $domain) !== false) continue;     // Skip own links
                            if ( $link[0] == '?' ) continue;
                            if ( $link[0] != 'h' && $link[1] != 't' && $link[2] != 't' && $link[3] != 'p' && $link[0] != '/' && $link[1] != '/' ) continue;
                            
                            $t_code = md5($link);
                            $t = $link;
                        }
                        else  {
                            $t_code = md5($e->innertext);
                            $t = substr($e->innertext, 0, 255);
                        }
                        
                        $a['results']['SCRIPT'][$t_code] = $t;
                    }
                
                    unset($html);
                }
                //else die('errorr');
            }
            $a['status'] = true;
            $a['cms'] = $cms;
            if (count($a['results']['A'])) ksort($a['results']['A']);
            if (count($a['results']['IFRAME'])) sort($a['results']['IFRAME']);
            if (count($a['results']['SCRIPT'])) sort($a['results']['SCRIPT']);
        }
        
        
        return $a;
    }
    
    static public function SQL_query($con, $sql)
    {
        $a = @mysqli_query($con, $sql);
    
        if ($e = mysqli_errno($con)) return false;
    
        return $a;
    }
}



class SGAntiVirus_scanner
{
    public static  $scanner_version = '3.0';
    public static  $debug = true;
    
	public static  $bool_list = array(0 => 'FALSE', 1 => 'TRUE');
	
	public static $SITEGUARDING_SERVER = 'http://www.siteguarding.com/ext/antivirus/index.php';
    
    var $antivirus_version = '';
    var $antivirus_platform = '';
    var $antivirus_cms = '';
    
    var $work_dir = '';
    var $tmp_dir = '';
    var $membership = '';
    var $scan_path = '';
    var $access_key = '';
    var $domain = '';
    var $email = '';
    var $session_report_key = '';
    
    var $detected_cms = '';
    var $sql_server = '';
    var $sql_database = '';
    var $sql_username = '';
    var $sql_password = '';
    
    var $full_scan = false;
    var $content_scan = true;   // Content-based PHP detection (scan file bodies for PHP tags). Default ON.
    
    
    var $exclude_folders_real = array();
    
    var $license_info = array();
    
    public static $max_filesize = 1024000;  // in bytes
    
    
    
	public function AntivirusFinished()
	{
	    if (self::$debug) self::DebugLog('line');
        
	    $reason = error_get_last();
        if (self::$debug) self::DebugLog(print_r($reason, true));
		if (self::$debug) self::DebugLog('PHP process has been terminated');
		
		$fp = fopen($this->tmp_dir.'flag_terminated.tmp', 'w');
		$a = date("Y-m-d H:i:s")." Terminated";
		fwrite($fp, $a);
		fclose($fp);
        
        if ($reason['type'] == 1) echo 'Error: '.$reason['message'].' File: '.$reason['message'].' Line: '.$reason['line'];	
	}


	
	public function AntivirusFileLock()
	{
	    $lockFile = $this->tmp_dir.'antivirus_scan.lock';
		
		$lockFp = fopen($lockFile, 'w');
		
		flock($lockFp, LOCK_UN);
		unlink($lockFile);
	}
    


    
	public function scanner($check_session = true, $show_results = true)
	{
	    // Start scanning process
        error_reporting(0);
		ini_set('memory_limit', '256M');
        
        if (!defined('DIRSEP')) 
        {
    	    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') define('DIRSEP', '\\');
    		else define('DIRSEP', '/');
        }
        
        
		// Skip the 2nd scan process
		$lockFile = $this->tmp_dir.'antivirus_scan.lock';
		
		if (file_exists($lockFile) && (time() - filemtime($lockFile)) < 60*5)
		{
			$error_msg = 'Another Scanning Process in the memory. Exit.';
			if (self::$debug) self::DebugLog($error_msg);
			exit;
		}
		
		register_shutdown_function('self::AntivirusFileLock');
		
		$lockFp = fopen($lockFile, 'w');
        
        // Register any shutdown of the script
        register_shutdown_function('self::AntivirusFinished');
        
		
        
		$error_msg = 'Start Scan Process ver. '.$this->antivirus_version.' [scanner ver. '.self::$scanner_version.']';
		if (self::$debug) self::DebugLog($error_msg, true);
		
		
        
        // Load extra settings
		if (file_exists($this->work_dir.'settings.php'))
		{
			$error_msg = '=> Extra settings loaded';
			if (self::$debug) self::DebugLog($error_msg);
			
			require_once($this->work_dir.'settings.php');	
            
            if (count($avp_settings))
            {
                foreach ($avp_settings as $k => $v)
                {
                    $v_txt = $v;
                    if ($v === false) $v_txt = 'BOOL: false';
                    if ($v === true) $v_txt = 'BOOL: true';
                    
            		$error_msg = 'Setting Value: '.strtoupper($k).' = '.$v_txt;
            		if (self::$debug) self::DebugLog($error_msg);
                        
                    if (strtolower($v) == 'false') $v = false;
                    if (strtolower($v) == 'true') $v = true;
                    define(strtoupper($k), $v);
                }
            }
		}
        
        if ( isset($this->license_info['settings']) && trim($this->license_info['settings']) != '' )
        {
            if (self::$debug) self::DebugLog("Remote settings:\n".$this->license_info['settings']);
            
            // Parse the settings
            $remote_settings = explode("\n", trim($this->license_info['settings']));
            if (count($remote_settings))
            {
                foreach ($remote_settings as $v)
                {
                    $v = trim($v);
                    $v = explode(":", $v);
                    $v[0] = trim($v[0]);
                    $v[1] = trim($v[1]);
                    if (strtolower($v[1]) == 'false') $v[1] = false;
                    if (strtolower($v[1]) == 'true') $v[1] = true;
                    define(strtoupper($v[0]), $v[1]);
                }
            }
        }
        
        
        // Set some constants
        if (!defined('DEBUG_FLAG')) define('DEBUG_FLAG', false);
        if (!defined('DEBUG_FILELIST')) define('DEBUG_FILELIST', false);
        if (!defined('CALLBACK_PACK_FILE')) define('CALLBACK_PACK_FILE', false);
        if (!defined('SCAN_SQL')) define('SCAN_SQL', true);
        if (!defined('FULL_SCAN')) define('FULL_SCAN', $this->full_scan);
        if (!defined('CONTENT_SCAN')) define('CONTENT_SCAN', $this->content_scan);
        // Content sniff: files larger than this are not body-scanned for PHP tags (in bytes)
        if (!defined('SG_PHP_SNIFF_MAXSIZE')) define('SG_PHP_SNIFF_MAXSIZE', 300 * 1024);
        // How many bytes to read for the content sniff. 0 = read the whole file (up to SG_PHP_SNIFF_MAXSIZE).
        // Set to e.g. 65536 to only read a 64KB header (faster, but misses payloads appended at the end of a file).
        if (!defined('SG_PHP_SNIFF_READ')) define('SG_PHP_SNIFF_READ', 0);
        

		// Analyze of exclude folders
		if (file_exists($this->work_dir.'exclude_folders.php'))
		{
			$error_msg = '=> Exclude folders file loaded';
			if (self::$debug) self::DebugLog($error_msg);
			
			require_once($this->work_dir.'exclude_folders.php');	
		}
		
	
		$tmp_result = set_time_limit ( 7200 );
		
		$error_msg = 'Change Time limit: '.self::$bool_list[intval($tmp_result)].' , Value: '.ini_get('max_execution_time');
		if (self::$debug) self::DebugLog($error_msg);
		
		$error_msg = 'Current Memory limit: '.ini_get('memory_limit');
		if (self::$debug) self::DebugLog($error_msg);

		$error_msg = 'OS info: '.PHP_OS.' ('.php_uname().')';
		if (self::$debug) self::DebugLog($error_msg);
		
		$error_msg = 'PHP ver: '.PHP_VERSION;
		if (self::$debug) self::DebugLog($error_msg);
		
        $tmp_file = $this->tmp_dir.'flag_terminated.tmp';
		if (file_exists($tmp_file)) unlink($tmp_file);
        $tmp_file = $this->tmp_dir.'filelist_'.md5($this->access_key).'.txt';
        if (file_exists($tmp_file)) unlink($tmp_file);
		
		// Remove old version logs
		if (file_exists($this->tmp_dir.'filelist.txt')) unlink($this->tmp_dir.'filelist.txt');
		if (file_exists($this->tmp_dir.'debug.log')) unlink($this->tmp_dir.'debug.log');
		if (file_exists($this->tmp_dir.'pack.zip')) unlink($this->tmp_dir.'pack.zip');
		if (file_exists($this->tmp_dir.'pack.tar')) unlink($this->tmp_dir.'pack.tar');
		if (file_exists($this->tmp_dir.'report_excluded_folders.php')) unlink($this->tmp_dir.'report_excluded_folders.php');
		if (file_exists($this->tmp_dir.'report_excluded_files.php')) unlink($this->tmp_dir.'report_excluded_files.php');
		if (file_exists($this->tmp_dir.'report_unwanted_files.php')) unlink($this->tmp_dir.'report_unwanted_files.php');
		if (file_exists($this->tmp_dir.'report_notreadable_files.php')) unlink($this->tmp_dir.'report_notreadable_files.php');
		if (file_exists($this->tmp_dir.'antivirus_error.log')) unlink($this->tmp_dir.'antivirus_error.log');
		if (file_exists($this->tmp_dir.'report_sql_results.php')) unlink($this->tmp_dir.'report_sql_results.php');
		if (file_exists($this->tmp_dir.'report_wordpress_check.php')) unlink($this->tmp_dir.'report_wordpress_check.php');
		if (file_exists($this->tmp_dir.'report_joomla_check.php')) unlink($this->tmp_dir.'report_joomla_check.php');
        
        $SCAN_SQL = SCAN_SQL;
        if (self::$debug)
        {
            if ($SCAN_SQL === true) $error_msg = 'SCAN_SQL: true';
            else $error_msg = 'SCAN_SQL: false';
            self::DebugLog($error_msg);
        }
        
        if (FULL_SCAN) $error_msg = 'FULL_SCAN: true';
        else $error_msg = 'FULL_SCAN: false';
		if (self::$debug) self::DebugLog($error_msg);
        
        if (CONTENT_SCAN) $error_msg = 'CONTENT_SCAN: true (read up to '.SG_PHP_SNIFF_MAXSIZE.' bytes, read window: '.(SG_PHP_SNIFF_READ == 0 ? 'whole file' : SG_PHP_SNIFF_READ.' bytes').')';
        else $error_msg = 'CONTENT_SCAN: false';
		if (self::$debug) self::DebugLog($error_msg);
        
        // Environment / extensions diagnostics
        if (self::$debug) self::CheckEnvironment();
        
        
        
		// Some Init data
		$membership = $this->membership;
		$scan_path = $this->scan_path; 
		$access_key = $this->access_key;
		$domain = $this->domain;
		$email = $this->email;
		$session_report_key = $this->session_report_key; 
		
			// Some logs
			$error_msg = 'Domain: '.$domain;
			if (self::$debug) self::DebugLog($error_msg);
			
			$error_msg = 'Scan path: '.$scan_path;
			if (self::$debug) self::DebugLog($error_msg);
			
			$error_msg = 'Session report key: '.$session_report_key;
			if (self::$debug) self::DebugLog($error_msg);
            
			$error_msg = 'Report URL: https://www.siteguarding.com/antivirus/viewreport?report_id='.$session_report_key;
			if (self::$debug) self::DebugLog($error_msg);
			
			$error_msg = 'TMP folder: '.$this->tmp_dir;
			if (self::$debug) self::DebugLog($error_msg);
            
            
		if (file_exists($scan_path.'.htaccess.siteguarding')) 
        {
            $error_msg = 'Found: .htaccess.siteguarding';
            if (self::$debug) self::DebugLog($error_msg);
            
            if (!rename( $scan_path.'.htaccess.siteguarding', $scan_path.'.htaccess'))
            {
                $error_msg = 'Cant rename: .htaccess.siteguarding -> .htaccess';
                if (self::$debug) self::DebugLog($error_msg);
            }
        }
            
			
		if (trim($domain) == '') {$error_msg = 'Domain is empty. Please contact SiteGuarding.com support.';echo $error_msg;if (self::$debug) self::DebugLog($error_msg);exit;}
		if (trim($session_report_key) == '') {$error_msg = 'Session key is empty. Please contact SiteGuarding.com support.';echo $error_msg;if (self::$debug) self::DebugLog($error_msg);exit;}
		if (trim($scan_path) == '') {$error_msg = 'Scan Path is empty. Please contact SiteGuarding.com support.';echo $error_msg;if (self::$debug) self::DebugLog($error_msg);exit;}
		
        
        if (file_exists($this->tmp_dir.'antivirus_sql.lock')) 
        {
            $error_msg = 'Found Lock file: antivirus_sql.lock';
            if (self::$debug) self::DebugLog($error_msg);
            
            $SCAN_SQL = false;
            
            if ( (time() - filectime($this->tmp_dir.'antivirus_sql.lock')) > 14*24*60*60)   // 14days
            {
                unlink($this->tmp_dir.'antivirus_sql.lock');
                $SCAN_SQL = true;
            }
        }
            
        if ($SCAN_SQL)
        {
            // Get CMS
            $detected_CMS = SGAntiVirus_SQL_scanner::DetectCMS();
            
            $error_msg = 'Detected CMS: '.$detected_CMS;
            if (self::$debug) self::DebugLog($error_msg);
            
            if ($detected_CMS == 'other')
            {
                $SCAN_SQL = false;
                $error_msg = 'SCAN_SQL: turned OFF [reason: unsupported CMS]';
                if (self::$debug) self::DebugLog($error_msg);
            }
        }
        else {
            $error_msg = 'SCAN_SQL: false';
            if (self::$debug) self::DebugLog($error_msg);
        }

		//session_start();
		$current_task = 0;
		$total_tasks = 0;
		$total_tasks += 1;	// Analyze what way to use for packing
		$total_tasks += 1;	// Pack files
		$total_tasks += 1;	// Send files
		$total_tasks += 1;	// Get report
		if ($SCAN_SQL) $total_tasks += 1;	// scan SQL

		
		/**
		 * Analyze SQL
		 */
        if ($SCAN_SQL) 
        {
    		// Update progress
    		$current_task += 1;
    		self::UpdateProgressValue($current_task, $total_tasks, 'Checking SQL.');
            
            $error_msg = 'Start SQL scan';
            if (self::$debug) self::DebugLog($error_msg);
            
            $fp = fopen($this->tmp_dir.'antivirus_sql.lock', 'w');
            fwrite($fp, '0');
            fclose($fp);

            // Get database settings
            $error_msg = 'Get SQL settings';
            if (self::$debug) self::DebugLog($error_msg);
            $sql_settings = SGAntiVirus_SQL_scanner::GetSQLsettings($detected_CMS);
            
            $error_msg = 'Read SQL records';
            if (self::$debug) self::DebugLog($error_msg);
            $sql_results = SGAntiVirus_SQL_scanner::ScanSQLContent($domain, $sql_settings, $detected_CMS);
            if ($sql_results['status'] === true)
            {
        		$file_sql_results = $this->tmp_dir.'report_sql_results.php';
        
        		$fp = fopen($file_sql_results, 'w');
        		$status = fwrite($fp, "<?php die(); ?>\n".json_encode($sql_results['results']));
        		fclose($fp);
                
                if ($detected_CMS == 'wordpress' || $detected_CMS == 'joomla') $error_msg = 'Detected: A='.count($sql_results['results']['A']).', IFRAME='.count($sql_results['results']['IFRAME']).', SCRIPT='.count($sql_results['results']['SCRIPT']).', TOTAL_JS='.$sql_results['results']['TOTAL_JS'];
                if ($detected_CMS == 'magento') $error_msg = 'Detected blocks with scripts: '.count($sql_results['results']['data']);
                if (self::$debug) self::DebugLog($error_msg);

                
                // Check core, plugins, themes, admins
                if ($detected_CMS == 'wordpress')
                {
                    $error_msg = 'SQL WordPress check: core, plugins, themes, admins';
                    if (self::$debug) self::DebugLog($error_msg);
                    
                    $check_wordpress = new Siteguarding_Wordpress_Core_Check($sql_settings);
                    $result = $check_wordpress->getFullResultsToArray();
                    
                        $error_msg = 'SQL WP options: home='.$result['options']['home'].', siteurl='.$result['options']['siteurl'].', admin_email='.$result['options']['admin_email'];
                        if (self::$debug) self::DebugLog($error_msg);
                        
                        $domain_only = self::PrepareDomain($domain);
                        
                        $tmp_1 = stripos($result['options']['home'], $domain_only);
                        $tmp_2 = stripos($result['options']['siteurl'], $domain_only);
                        
                        if ( $tmp_1 === false || $tmp_1 > 20 || $tmp_2 === false || $tmp_2 > 20) $result['options']['redirect_detected'] = 1;
                        else $result['options']['redirect_detected'] = 0;
                        
                        unset($result['options']['home']);
                        unset($result['options']['siteurl']);
                        
                        if ($result['options']['redirect_detected'] == 1)
                        {
                            $error_msg = '!!! ALERT !!! WP Redirect detected ('.$domain_only.') t1='.$tmp_1.', t2='.$tmp_2;
                            if (self::$debug) self::DebugLog($error_msg);
                        }
                        
                    
            		$file_sql_results = $this->tmp_dir.'report_wordpress_check.php';
            		$fp = fopen($file_sql_results, 'w');
            		$status = fwrite($fp, "<?php die(); ?>\n".json_encode($result));
            		fclose($fp);
                    
                    unset($check_wordpress);
                    unset($result);
                }
                if ($detected_CMS == 'joomla')
                {
                    $error_msg = 'SQL Joomla check: core, admins';
                    if (self::$debug) self::DebugLog($error_msg);
                    
                    $check_joomla = new Siteguarding_Joomla_Core_Check($sql_settings);
                    $result = $check_joomla->getFullResultsToArray();
                    
            		$file_sql_results = $this->tmp_dir.'report_joomla_check.php';
            		$fp = fopen($file_sql_results, 'w');
            		$status = fwrite($fp, "<?php die(); ?>\n".json_encode($result));
            		fclose($fp);
                    
                    unset($check_joomla);
                    unset($result);
                }
                
                
            }
            else {
                $error_msg = 'ScanSQLContent returned error: '.$sql_results['reason'];
                if (self::$debug) self::DebugLog($error_msg);
            }
            
            

            
            unlink($this->tmp_dir.'antivirus_sql.lock');
        }

         
		/**
		 * Analyze what way to use for packing
		 */
	 	$ssh_flag = false;
		if ( function_exists('exec') ) 
		{
			// Pack files with ssh 
			$ssh_flag = true;
		}
        if (defined('SETTINGS_ONLY_ZIP') && SETTINGS_ONLY_ZIP) $ssh_flag = false;
		// Update progress
		$current_task += 1;
		self::UpdateProgressValue($current_task, $total_tasks, 'Initialization.');
		
        
        if (self::$debug) self::DebugLog('line');
        


		/**
		 * Collecting information about the files 
		 */
        if (isset($_REQUEST['files_list']) && $_REQUEST['files_list'] != '') 
        {
            // Scan provided files
    		$error_msg = 'File list is provided [strlen: '.strlen($_REQUEST['files_list']).' bytes]';
    		if (self::$debug) self::DebugLog($error_msg);
            
            $files_list = trim($_REQUEST['files_list']);
            $files_list = (array)json_decode($files_list);
        }   
        else {  
            $files_list = array();
            if (defined('DEBUG_FILELIST') && DEBUG_FILELIST) self::DebugFile($this->work_dir, true);
            
    		$error_msg = 'Collecting info about the files [METHOD 2]';
    		if (self::$debug) self::DebugLog($error_msg);        
            
            
            $exclude_folders_real = array();
            if (!isset($exclude_folders) || !is_array($exclude_folders)) $exclude_folders = array();
    		if (count($exclude_folders))
    		{
    			foreach ($exclude_folders as $k => $ex_folder)
    			{
    				$ex_folder = $scan_path.trim($ex_folder);
    				$exclude_folders_real[$k] = trim(str_replace(DIRSEP.DIRSEP, DIRSEP, $ex_folder));	
    			}
    		}
    		else $exclude_folders_real = array(); 
            
                if (defined('SCAN_ALL_SITES') && SCAN_ALL_SITES == 1) 
                {
                    // No action
                }
                else {
                    // Exclude other sites from this scan
            		$error_msg = 'Check for other websites';
            		if (self::$debug) self::DebugLog($error_msg); 
                    
                    $dir_array = array();
                    if ($currentDir = opendir($scan_path)) 
                    {
                        while ($file = readdir($currentDir)) 
                        {
                            if (is_dir($scan_path.$file)) 
                            {
                                if ($file == '.' || $file == '..') continue;
                                $dir_array[] = $file;
                            }
                    
                        }
                        closedir($currentDir);
                    }
                    sort($dir_array);
                    
                    $cms_dirs = array();
                    
                    foreach ($dir_array as $folder)
                    {
                    	if ( file_exists( $scan_path.DIRSEP.$folder.DIRSEP."configuration.php" ) || file_exists( $scan_path.DIRSEP.$folder.DIRSEP."wp-config.php" ) )
                    	{
                    		$cms_dirs[] = DIRSEP.$folder.DIRSEP;
                    	}
                    }
                    
                    if (count($cms_dirs))
                    {
                		$error_msg = 'Found '.count($cms_dirs).' websites';
                		if (self::$debug) self::DebugLog($error_msg); 
                        
            			foreach ($cms_dirs as $k => $ex_folder)
            			{
            				$ex_folder = $scan_path.trim($ex_folder);
                            $ex_folder = trim(str_replace(DIRSEP.DIRSEP, DIRSEP, $ex_folder));
                            if (!in_array($ex_folder, $exclude_folders_real)) $exclude_folders_real[] = $ex_folder;
            			}
                    }
                }  
                 
                                // Remote exclude folders
                                if (defined('EXCLUDE_FOLDERS'))
                                {
                                    $remote_excluded_folders = explode(",", EXCLUDE_FOLDERS);
                                    if ( count($remote_excluded_folders))
                                    {
                            			foreach ($remote_excluded_folders as $k => $ex_folder)
                            			{
                            				$ex_folder = $scan_path.trim($ex_folder);
                                            $ex_folder = trim(str_replace(DIRSEP.DIRSEP, DIRSEP, $ex_folder));
                                            if (!in_array($ex_folder, $exclude_folders_real)) $exclude_folders_real[] = $ex_folder;
                            			}
                                    }
                                }
                                
                                        // Remote include folders
                                        if (defined('INCLUDE_FOLDERS'))
                                        {
                                            $remote_included_folders = explode(",", INCLUDE_FOLDERS);
                                            if ( count($remote_included_folders))
                                            {
                                    			foreach ($remote_included_folders as $k => $in_folder)
                                    			{
                                    				$in_folder = $scan_path.trim($in_folder);
                                                    $in_folder = trim(str_replace(DIRSEP.DIRSEP, DIRSEP, $in_folder));
                                                    if (in_array($in_folder, $exclude_folders_real)) 
                                                    {
                                                        unset( $exclude_folders_real[array_search($in_folder, $exclude_folders_real)] );
                                                    }
                                    			}
                                            }
                                        }
            
            // Check if exluded folders are on the server
            if (count($exclude_folders_real))
            {
                $exclude_folders_real_short = array();
                foreach($exclude_folders_real as $k => $v)
                {
                    if (!file_exists($v)) unset($exclude_folders_real[$k]);
                    else $exclude_folders_real_short[] = str_replace($scan_path, DIRSEP, $v);
                }
                
                if (defined('HIDE_EXCLUDE_ALERT') && HIDE_EXCLUDE_ALERT == 1) 
                {
                    // Empty
                }
                else {
            		$file_report_excluded_folders = $this->tmp_dir.'report_excluded_folders.php';
            
            		$fp = fopen($file_report_excluded_folders, 'w');
            		$status = fwrite($fp, "<?php die(); ?>\n".json_encode($exclude_folders_real_short));
            		fclose($fp);
                }
            }
            
            $this->exclude_folders_real = $exclude_folders_real; 
            
            
    		$error_msg = 'Excluded Folders: '.count($exclude_folders_real);
    		if (self::$debug) self::DebugLog($error_msg);
    		
    		$error_msg = print_r($exclude_folders_real, true);
    		if (self::$debug && count($exclude_folders_real) > 0) self::DebugLog($error_msg); 
            
            $dirList = array();
            $dirList[] = $scan_path;
            
            
     
                    
            // Scan all dirs
            while (true) 
            {
                $dirList = array_merge(self::ScanFolder(array_shift($dirList), $files_list), $dirList);
                if (count($dirList) < 1) break;
            }
            
            
    		$error_msg = 'Save collected file_list';
    		if (self::$debug) self::DebugLog($error_msg);
        }
        // END colleting the files



		$collected_filelist = $this->tmp_dir.'filelist_'.md5($this->access_key).'.txt';

		$fp = fopen($collected_filelist, 'w');
		$status = fwrite($fp, implode("\n", $files_list));
		fclose($fp);
		if ($status === false)
		{
			$error_msg = 'Cant save information about the collected files '.$collected_filelist;
			if (self::$debug) self::DebugLog($error_msg);
			
			// Turn ZIP mode
			$ssh_flag = false;
		}
		
		$error_msg = 'Total files: '.count($files_list);
		if (self::$debug) self::DebugLog($error_msg);
         
        
        

        
        


        if (self::$debug) self::DebugLog('line');



	
		if ($ssh_flag)
		{
			// SSH way
				$error_msg = 'Start - Pack with SSH';
				if (self::$debug) self::DebugLog($error_msg);
				
			$cmd = 'cd '.$scan_path.''."\n".'tar -czf '.$this->tmp_dir.'pack_'.md5($this->access_key).'.tar -T '.$collected_filelist;
			$output = array();
			$result = exec($cmd, $output);
			
			if (file_exists($this->tmp_dir.'pack_'.md5($this->access_key).'.tar') === false || filesize($this->tmp_dir.'pack_'.md5($this->access_key).'.tar') < 512) 
			{
				$ssh_flag = false;
				
				$error_msg = 'Change pack method from SSH to PHP (ZipArchive)';
				if (self::$debug) self::DebugLog($error_msg);
                
				$error_msg = 'exec output: '.print_r($output, true);
				if (self::$debug) self::DebugLog($error_msg);
			}
		}
		
        
        
    	if (!$ssh_flag) 
    	{
    		// PHP way
    			$error_msg = 'Start - Pack with ZipArchive';
    			if (self::$debug) self::DebugLog($error_msg);
    		
    	    	$file_zip = $this->tmp_dir.'pack_'.md5($this->access_key).'.zip';
    	    	if (file_exists($file_zip)) unlink($file_zip);
    	    	$pack_dir = $scan_path;
                
                	
    	    if (class_exists('ZipArchive') && ( ( !defined('DISABLE_ZIPARCHIVE') ) || ( defined('DISABLE_ZIPARCHIVE') && DISABLE_ZIPARCHIVE === false ) ) )
    	    {
    	        // open archive
    	        $zip = new ZipArchive;
    	        if ($zip->open($file_zip, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE) === TRUE) 
    	        {
    	            foreach ($files_list as $file_name) 
    	            {
    	            	$file_name = $this->scan_path.$file_name;
    	                if( strstr(realpath($file_name), "stark") == FALSE) 
    					{
    						$short_key = str_replace($scan_path, "", $file_name);
    	                	$s = $zip->addFile(realpath($file_name), $short_key);
    		                if (!$s) 
    		                {
    		                	$error_msg = 'Couldnt add file: '.$file_name; 
    		                	if (self::$debug) self::DebugLog($error_msg);
    		                }
    	            	}
    					
    				}
    	             // close and save archive
    	            $zip->close();
    	            
    	            //$result['msg'][] = 'Archive created successfully'; 
    	        }
    	        else {
    	        	$error_msg = 'Error: Couldnt open ZIP archive.';
    	        	//echo $error_msg;
    	            self::UpdateProgressValue($current_task, $total_tasks, $error_msg);
    				if (self::$debug) self::DebugLog($error_msg);
    				exit;
    	        }
    	
    	    }
    	    else {
    	    	$error_msg =  'Error: ZipArchive class is not exist.';
    	        if (self::$debug) self::DebugLog($error_msg);
    	    }
    	    
    		$error_msg = 'ZipArchive method - finished';
    		if (self::$debug) self::DebugLog($error_msg);
    		
    		// Check if zip file exists
    		if (!file_exists($file_zip))
    		{
    			$error_msg = 'Error: zip file is not exists. Use OwnZipClass';
    			if (self::$debug) self::DebugLog($error_msg);
    			
    			$error_msg = 'OwnZipClass method - started';
    			if (self::$debug) self::DebugLog($error_msg);
                
    				$zip = new ZipSGAVP();
    				$zip->setZipFile($file_zip);
    	            foreach ($files_list as $file_name_short) 
    	            {
    	            	$file_name = trim($this->scan_path.$file_name_short);
						
							if (defined('DEBUG_ZIP_ADDFILES') && DEBUG_ZIP_ADDFILES === true)
							{
								$error_msg = 'Zip Add: '.$file_name;
								if (self::$debug) self::DebugLog($error_msg);
							}
							
    	            	$handle = @fopen($file_name, "rb");
    	            	if ($handle === false)
    	            	{
    	            		if (self::$debug) self::DebugLog('Zip Add: cannot open '.$file_name);
    	            		continue;
    	            	}
    	            	$fsize = filesize($file_name);
    	            	if ($fsize > 0)
    	            	{
    	            		$data = fread($handle, $fsize);
    	            		if ($data !== false) $zip->addFile($data, $file_name_short, filectime($file_name), NULL, TRUE, ZipSGAVP::getFileExtAttr($file_name));
    	            	}
    	            	fclose($handle);
    	           	}
    	           	$zip->finalize();
               	
    			$error_msg = 'OwnZipClass method - finished';
    			if (self::$debug) self::DebugLog($error_msg);
                
                $ssh_flag = false; 
    		}
    		
    	}
        
        
        
        
        
		// Update progress
		$current_task += 1;
		self::UpdateProgressValue($current_task, $total_tasks, 'Collecting information about the files.');


		/**
		 * Send files to SG server
		 */
        $disabled_functions = ini_get('disable_functions');
		$error_msg = 'php disable_functions: '.$disabled_functions;
        if (self::$debug) self::DebugLog($error_msg);
        if (stripos($disabled_functions, 'curl') !== false)
        {
            $error_msg = '!!! CURL is in disabled functions';
            if (self::$debug) self::DebugLog($error_msg);
        }
		
        
		if ($ssh_flag)
		{
	 		$archive_filename = $this->tmp_dir.'pack_'.md5($this->access_key).'.tar';
	 		$archive_format = 'tar';
		} else {
			$archive_filename = $this->tmp_dir.'pack_'.md5($this->access_key).'.zip';
			$archive_format = 'zip';
		}
		$error_msg = 'Pack file: '.$archive_filename;
		if (self::$debug) self::DebugLog($error_msg);

		
	 	
	 	// Check if pack file is exist
		if (file_exists($archive_filename) === false) 
		{
			$error_msg = 'Error: Pack file is not exist. Probably not enough space on the server.';
			if (self::$debug) self::DebugLog($error_msg);
			echo $error_msg;
			exit;
		}
        
		$tar_size = filesize($archive_filename);
		$error_msg = 'Pack file is '.round($tar_size/1024/1024, 2).'Mb';
		if (self::$debug) self::DebugLog($error_msg);
        
        
        
        if (self::$debug) self::DebugLog('line');
		
		
		
		$error_msg = 'Start - Send Packed files to SG server';
		if (self::$debug) self::DebugLog($error_msg);
		
        $archive_file_url = "/".str_replace($this->scan_path, "", $this->tmp_dir).'pack_'.md5($this->access_key).'.'.$archive_format;
        $archive_file_url = str_replace("\\", "/", $archive_file_url);
		$error_msg = 'Pack URL: '.$archive_file_url;
		if (self::$debug) self::DebugLog($error_msg);
		
		if ($tar_size < 64 * 1024 * 1024 || $membership == 'pro')
    	{
    		// Send file
    		$post_data = base64_encode(json_encode(array(
    				'domain' => $domain,
    				'access_key' => $access_key,
    				'email' => $email,
    				'session_report_key' => $session_report_key,
    				'archive_format' => $archive_format,
    				'archive_file_url' => $archive_file_url))
    		);
    
    		$flag_CallBack = false;
    		if (defined('CALLBACK_PACK_FILE') && CALLBACK_PACK_FILE )
    		{	// Callback option
    			$flag_CallBack = true;
    		}
    		else {
    			$result = self::UploadSingleFile($archive_filename, 'uploadfiles_ver2', $post_data);
    			if ($result === false)
    			{
    				$error_msg = 'Can not upload pack file for analyze';
    				if (self::$debug) self::DebugLog($error_msg);
    				
    				$flag_CallBack = true;
    			}
    			else {
    				$error_msg = 'Pack file sent for analyze - OK';
    				if (self::$debug) self::DebugLog($error_msg);
    				
    				$flag_CallBack = false;
    			}
    		}
    		
    		
    		// CallBack method
    		if ($flag_CallBack)
    		{
    			$error_msg = 'Start to use CallBack method';
    			if (self::$debug) self::DebugLog($error_msg);
    			
    			
    			$post_data = base64_encode(json_encode(array(
    					'domain' => $domain,
    					'access_key' => $access_key,
    					'email' => $email,
    					'session_report_key' => $session_report_key,
    					'archive_format' => $archive_format,
    					'archive_file_url' => $archive_file_url))
    			);
    			
    			$result = self::UploadSingleFile_Callback($post_data);
    			
    			if ($result === false)
    			{
    				$error_msg = 'CallBack method - failed';
    				if (self::$debug) self::DebugLog($error_msg);
    				
    				$error_msg = 'Can not upload pack file for analyze';
    				if (self::$debug) self::DebugLog($error_msg);
    				echo $error_msg;
    				exit;
    			}
    			else {
    				$error_msg = 'CallBack method - OK';
    				if (self::$debug) self::DebugLog($error_msg);
    			}
    			
    		}
    
    		
    	}
		else {
			$error_msg = 'Pack file is too big ('.$error_msg.'), please contact SiteGuarding.com support or upgrade to PRO version.';
			if (self::$debug) self::DebugLog($error_msg);
			echo $error_msg;
            $error_msg = 'Website is huge or hosting account has other sites. Free version has limits. Contact SiteGuarding.com support.';
            self::ErrorLog($error_msg);
			exit;
		}
		// Update progress
		$current_task += 1;
		self::UpdateProgressValue($current_task, $total_tasks, 'Analyzing the files. Preparing the report.');
		




        if (self::$debug) self::DebugLog('line');
        

		/**
		 * Check and Get report from SG server
		 */
		$error_msg = 'Start - Report generating';
		if (self::$debug) self::DebugLog($error_msg);
		
        $use_https_flag = false;
		for ($i = 1; $i <= 10*60; $i++)
		{
			sleep(5);
            
    		$post_data = base64_encode(json_encode(array(
    				'domain' => $domain,
    				'access_key' => $access_key,
    				'session_report_key' => $session_report_key)));
                    
            $link = self::$SITEGUARDING_SERVER.'?action=getreport_ver2';
            
            $client = EasyRequest_AVP::create('POST', $link, array(
                'form_params' => array(
                    'data' => $post_data,
                ),
            ));
            $client->send();
            $http_status = $client->getResponseStatus();
            $result_json = trim($client->getResponseBody());
            
			
			$result_json = (array)json_decode($result_json, true);

			if ($result_json['status'] == 'ready') 
			{
				echo $result_json['text'];
                
				// Update progress
				$current_task += 1;
				self::UpdateProgressValue($current_task, $total_tasks, 'Done. Sending your report.');
				
				$error_msg = 'Done. Sending your report by email';
				if (self::$debug) self::DebugLog($error_msg);
				
				// Send email to user with the report
				$email_result = self::SendEmail($email, $result_json['text']);
                
				if ($email_result) $error_msg = 'Report Sent - OK';
                else $error_msg = 'Report Sent - FAILED'; 
				if (self::$debug) self::DebugLog($error_msg);
				
				exit;	
			}
		}
		
		$error_msg = 'Finished [Report is not sent]'."\n";
		if (self::$debug) self::DebugLog($error_msg);
    }
    
    
    
    
    
    function ScanFolder($path, &$files_list)
    {
        $dirList = array();
    
        if ($currentDir = opendir($path)) 
        {
            while ( false !== ( $file = readdir($currentDir) ) ) 
            {
                if ( $file === '.' || $file === '..' || is_link($path) ) continue;
                $file = $path . '/' . $file;
    
                
                if (is_dir($file)) 
                {
                    $folder = $file.DIRSEP;
                    $folder = str_replace(DIRSEP.DIRSEP, DIRSEP, $folder);
                    
                    // Exclude folders
                    if (count($this->exclude_folders_real))
                    {
                 		if (in_array($folder, $this->exclude_folders_real)) 
        				{
        				    if (self::$debug) self::DebugLog('--- '.$folder);
                            continue;
        				}
        				else if (self::$debug) self::DebugLog('+++ '.$folder);
                    }
                    $dirList[] = $file;
                    if (defined('DEBUG_FILELIST') && DEBUG_FILELIST) self::DebugFile($file);
                }
                else {
                    
                    if (is_link($file))
                    {
                        self::DebugLog('Symbolic link: '.$file);
                        continue;
                    }
                    
					//if (strpos($file, '.php.') || strpos($file, '.phtml.') || strpos($file, '.php3.') || strpos($file, '.php4.') || strpos($file, '.php5.'))
					if (strpos($file, '.php') || strpos($file, '.phtml') || strpos($file, '.shtml'))
					{
					    $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
                        
					    $file_size = filesize($file);
                        if ($file_size > self::$max_filesize)
                        {
                            if ($ext == 'gzs') continue;
                            
                            self::DebugLog('Big file: '.str_replace($this->scan_path, "", $file).' ['.$file_size.' bytes]');
                            self::HugeFilesLog(str_replace($this->scan_path, "", $file));
                            continue;
                        }
                        
                        
                        switch ($ext)
                        {
                            case 'tar':
                            case '7z':
                            case 'exe':
                            case 'gz':
                            case 'gzip':
                            case 'pak':
                            case 'pkg':
                            case 'rar':
                            case 'tar-gz':
                            case 'tgz':
                            case 'zip':
                            
                            case 'gzs':
                                self::DebugLog('Excluded ext: '.$file);
                                continue 2;
                        }
                        
                        if (!is_readable($file))
                        {
                            self::DebugLog('NOT readable: '.$file);
                            self::NotReadableFilesLog(str_replace($this->scan_path, "", $file));
                            continue;
                        }
                        
                        if (strlen($this->scan_path) > 1) $file = str_replace($this->scan_path, "", $file);
        				if ($file != '' && ($file[0] == "\\" || $file[0] == "/")) $file = substr($file, 1);
        				$files_list[] = $file;
					}
					else {
                        // Check extension
                        $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
                        switch ($ext)
                        {
                            case 'ico':
                            
                            case 'inc':
                            case 'php':
                            case 'php4':
                            case 'php5':
                            case 'phtml':
                            case 'shtml':
                            case 'js':
                            case 'html':
                            case 'htm':
                            case 'cgi':
                            case 'pl':
                            case 'sh':
                            case 'htaccess':
                            
                            case 'module':
                            case 'install':
                            
        					    $file_size = filesize($file);
                                if ($file_size > self::$max_filesize)
                                {
                                    self::DebugLog('Big file: '.str_replace($this->scan_path, "", $file).' ['.$file_size.' bytes]');
                                    self::HugeFilesLog(str_replace($this->scan_path, "", $file));
                                    continue 2;
                                }
                                
                                if (!is_readable($file))
                                {
                                    self::DebugLog('NOT readable: '.$file);
                                    self::NotReadableFilesLog(str_replace($this->scan_path, "", $file));
                                    continue 2;
                                }
                                
                                if (strlen($this->scan_path) > 1) $file = str_replace($this->scan_path, "", $file);
                				if ($file != '' && ($file[0] == "\\" || $file[0] == "/")) $file = substr($file, 1);
                				$files_list[] = $file;
                                break;
                                
                            
                            case 'so':
                            case 'exe':
                                self::DebugLog('Unwanted file: '.str_replace($this->scan_path, "", $file));
                                self::UnwantedFilesLog(str_replace($this->scan_path, "", $file));
                                continue 2;
                                
                            case '':
                                $handle = @fopen($file, "rb");
                                if ($handle === false)
                                {
                                    self::DebugLog('NOT readable: '.$file);
                                    self::NotReadableFilesLog(str_replace($this->scan_path, "", $file));
                                    continue 2;
                                }
                                $contents = @fread($handle, 6);
                                @fclose($handle);
                                
                                if ($contents !== false && strpos($contents, 'ELF') !== false)
                                {
                                    self::DebugLog('Unwanted file: '.str_replace($this->scan_path, "", $file));
                                    self::UnwantedFilesLog(str_replace($this->scan_path, "", $file));
                                    continue 2;
                                }
                                
                            
                            default:
                                if (CONTENT_SCAN)
                                {
            					    $file_size = filesize($file);
                                    if ($file_size === false || $file_size <= 0) continue 2;
                                    if ($file_size > SG_PHP_SNIFF_MAXSIZE) continue 2;
                                    
                                    if (self::IsPhpByContent($file, $file_size))
                                    {
                                        if (strlen($this->scan_path) > 1) $file = str_replace($this->scan_path, "", $file);
                        				if ($file != '' && ($file[0] == "\\" || $file[0] == "/")) $file = substr($file, 1);
                        				$files_list[] = $file;
                                        
                                        self::DebugLog('*PHP code detected: '.str_replace($this->scan_path, "", $file).' ['.$file_size.' bytes]');
                                    }
									else {
                                        if (strlen($this->scan_path) > 1) $file = str_replace($this->scan_path, "", $file);
                        				if ($file != '' && ($file[0] == "\\" || $file[0] == "/")) $file = substr($file, 1);
										
										self::DebugLogFileList($file);
									}
                                }

                        }
                    }
                    
                }
    
            }
            closedir($currentDir);
        }
    
        return $dirList;
    }

    

    
    
    
    function DebugFile($file, $clean_log_file = false)
    {
		if ($clean_log_file) $fp = fopen($this->tmp_dir.'debug_filelist.log', 'w');
		else {
            $file = str_replace($this->scan_path, "", $file);
    	    $fp = fopen($this->tmp_dir.'debug_filelist.log', 'a');
		}

		$a = $file."\n";
		fwrite($fp, $a);
		fclose($fp); 
    }
    
    
    
    
    
	function UpdateProgressValue($current_task, $total_tasks, $current_step_txt)
	{
		$i = round( 100*$current_task/$total_tasks, 2 );
		
		$a = array(
			'txt' => $current_step_txt,
			'progress' => $i
		);
		
		$filename = $this->tmp_dir."antivirus_last_action.log";
		$fp = fopen($filename, 'w');
		fwrite($fp, json_encode($a));
		fclose($fp);
		
		sleep(3);
	}
    
    
    
    function UploadSingleFile($file, $action, $post_data)
    {
        $client = EasyRequest_AVP::create('POST', SITEGUARDING_SERVER.'?action='.$action, array(
            'multipart' => array(
                array(
                    'name' => 'data',
                    'contents' => $post_data
                ),
            )
        ));
        $client->withFormFile('file_contents', $file);
        
        $client->send(); 
        

        $http_status = $client->getResponseStatus();

		$error_msg = 'CURL info - '.print_r($client->getDebugInfo(), true);
		if (self::$debug) self::DebugLog($error_msg);
    
        if ($http_status != 200)
        {
    		$error_msg = 'HTTP Status =  '.$http_status;
    		if (self::$debug) self::DebugLog($error_msg);
            
            return false;
        }
        
        return true;
        
    }
    
    
    
    function UploadSingleFile_Callback($post_data)
    {
        $status = self::UploadSingleFile_Callback_extension($post_data);
        if ($status === false) $status = self::UploadSingleFile_Callback_extension($post_data, true);
        
        return $status;
    }
	
    function UploadSingleFile_Callback_extension($post_data, $https_flag = false)
    {
		$error_msg = 'Use HTTPS: '.self::$bool_list[intval($https_flag)];
		if (self::$debug) self::DebugLog($error_msg);
        
    	$link = self::$SITEGUARDING_SERVER;
        if ($https_flag === true) $link = str_replace("http://www.", "https://www.", $link);
    	$link = $link.'?action=uploadfiles_callback';
    	
        $result = GetRemote_file_contents($link, array('data' => $post_data));
    	
    	$result = json_decode(trim($result), true);
    	
    	if (self::$debug) self::DebugLog(print_r($result, true));
    	
    	if ($result['status'] == 'ok') return true;
    	else return false;
    }
	
    
    
    
    function SendEmail($email, $result, $subject = '')
    {
    	$to  = $email; // note the comma
    	
    	// subject
    	if ($subject == '') $subject = 'AntiVirus Report ['.date("Y-m-d H:i:s").']';
    	
    	// message
        $body_message = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SiteGuarding - Professional Web Security Services!</title>
</head>
<body bgcolor="#ECECEC" style="background-color:#ECECEC;">
<table cellpadding="0" cellspacing="0" width="100%" align="center" border="0" bgcolor="#ECECEC" style="background-color: #fff;">
  <tr>
    <td width="100%" align="center" bgcolor="#ECECEC" style="padding: 5px 30px 20px 30px;">
      <table width="750" border="0" align="center" cellpadding="0" cellspacing="0" bgcolor="#fff" style="background-color: #fff;">
        <tr>
          <td width="750" bgcolor="#fff"><table width="750" border="0" cellspacing="0" cellpadding="0" bgcolor="#fff" style="background-color: #fff;">
            <tr>
              <td width="350" height="60" bgcolor="#fff" style="padding: 5px; background-color: #fff;"><a href="http://www.siteguarding.com/" target="_blank"><img src="data:image/png;base64,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" alt="SiteGuarding - Protect your website from unathorized access, malware and other threat" height="60" border="0" style="display:block" /></a></td>
              <td width="400" height="60" align="right" bgcolor="#fff" style="background-color: #fff;">
              <table border="0" cellspacing="0" cellpadding="0" bgcolor="#fff" style="background-color: #fff;">
                <tr>
                  <td style="font-family:Arial, Helvetica, sans-serif; font-size:11px;"><a href="http://www.siteguarding.com/en/login" target="_blank" style="color:#656565; text-decoration: none;">Login</a></td>
                  <td width="15"></td>
                  <td width="1" bgcolor="#656565"></td>
                  <td width="15"></td>
                  <td style="font-family:Arial, Helvetica, sans-serif; font-size:11px;"><a href="http://www.siteguarding.com/en/prices" target="_blank" style="color:#656565; text-decoration: none;">Services</a></td>
                  <td width="15"></td>
                  <td width="1" bgcolor="#656565"></td>
                  <td width="15"></td>
                  <td style="font-family:Arial, Helvetica, sans-serif; font-size:11px;"><a href="http://www.siteguarding.com/en/what-to-do-if-your-website-has-been-hacked" target="_blank" style="color:#656565; text-decoration: none;">Security Tips</a></td>            
                  <td width="15"></td>
                  <td width="1" bgcolor="#656565"></td>
                  <td width="15"></td>
                  <td style="font-family:Arial, Helvetica, sans-serif;  font-size:11px;"><a href="http://www.siteguarding.com/en/contacts" target="_blank" style="color:#656565; text-decoration: none;">Contacts</a></td>
                  <td width="30"></td>
                </tr>
              </table>
              </td>
            </tr>
          </table></td>
        </tr>

        <tr>
          <td width="750" height="2" bgcolor="#D9D9D9"></td>
        </tr>
        <tr>
          <td width="750" bgcolor="#fff" ><table width="750" border="0" cellspacing="0" cellpadding="0" bgcolor="#fff" style="background-color:#fff;">
            <tr>
              <td width="750" height="30"></td>
            </tr>
            <tr>
              <td width="750">
                <table width="750" border="0" cellspacing="0" cellpadding="0" bgcolor="#fff" style="background-color:#fff;">
                <tr>
                  <td width="30"></td>
                  <td width="690" bgcolor="#fff" align="left" style="background-color:#fff; font-family:Arial, Helvetica, sans-serif; color:#000000; font-size:12px;">
                    {MESSAGE_CONTENT}
                    <br>
                    <b>URGENT SUPPORT</b><br>
                    Not sure in the report details? Need urgent help and support. Please contact us <a href="https://www.siteguarding.com/en/contacts" target="_blank">https://www.siteguarding.com/en/contacts</a>
                  </td>
                  <td width="30"></td>
                </tr>
              </table></td>
            </tr>
            <tr>
              <td width="750" height="15"></td>
            </tr>
            <tr>
              <td width="750" height="15"></td>
            </tr>
            <tr>
              <td width="750"><table width="750" border="0" cellspacing="0" cellpadding="0">
                <tr>
                  <td width="30"></td>
                  <td width="690" align="left" style="font-family:Arial, Helvetica, sans-serif; color:#000000; font-size:12px;"><strong>How can we help?</strong><br />
                    If you have any questions please dont hesitate to contact us. Our support team will be happy to answer your questions 24 hours a day, 7 days a week. You can contact us at <a href="mailto:support@siteguarding.com" style="color:#2C8D2C;"><strong>support@siteguarding.com</strong></a>.<br />
                    <br />
                    Thanks again for choosing SiteGuarding as your security partner!<br />
                    <br />
                    <span style="color:#2C8D2C;"><strong>SiteGuarding Team</strong></span><br />
                    <span style="font-family:Arial, Helvetica, sans-serif; color:#000; font-size:11px;"><strong>We will help you to protect your website from unauthorized access, malware and other threats.</strong></span></td>
                  <td width="30"></td>
                </tr>
              </table></td>
            </tr>
            <tr>
              <td width="750" height="30"></td>
            </tr>
          </table></td>
        </tr>
        <tr>
          <td width="750" height="2" bgcolor="#D9D9D9"></td>
        </tr>
      </table>
      <table width="750" border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td width="750" height="10"></td>
        </tr>
        <tr>
          <td width="750" align="center"><table border="0" cellspacing="0" cellpadding="0">
            <tr>
              <td style="font-family:Arial, Helvetica, sans-serif; color:#ffffff; font-size:10px;"><a href="http://www.siteguarding.com/en/website-daily-scanning-and-analysis" target="_blank" style="color:#656565; text-decoration: none;">Website Daily Scanning</a></td>
              <td width="15"></td>
              <td width="1" bgcolor="#656565"></td>
              <td width="15"></td>
              <td style="font-family:Arial, Helvetica, sans-serif; color:#ffffff; font-size:10px;"><a href="http://www.siteguarding.com/en/malware-backdoor-removal" target="_blank" style="color:#656565; text-decoration: none;">Malware & Backdoor Removal</a></td>
              <td width="15"></td>
              <td width="1" bgcolor="#656565"></td>
              <td width="15"></td>
              <td style="font-family:Arial, Helvetica, sans-serif; color:#ffffff; font-size:10px;"><a href="http://www.siteguarding.com/en/update-scripts-on-your-website" target="_blank" style="color:#656565; text-decoration: none;">Security Analyze & Update</a></td>
              <td width="15"></td>
              <td width="1" bgcolor="#656565"></td>
              <td width="15"></td>
              <td style="font-family:Arial, Helvetica, sans-serif; color:#ffffff; font-size:10px;"><a href="http://www.siteguarding.com/en/website-development-and-promotion" target="_blank" style="color:#656565; text-decoration: none;">Website Development</a></td>
            </tr>
          </table></td>
        </tr>

        <tr>
          <td width="750" height="10"></td>
        </tr>
        <tr>
          <td width="750" align="center" style="font-family: Arial,Helvetica,sans-serif; font-size: 10px; color: #656565;">Add <a href="mailto:support@siteguarding.com" style="color:#656565">support@siteguarding.com</a> to the trusted senders list.</td>
        </tr>
      </table>
    </td>
  </tr>
</table>
</body>
</html>
';

    	$body_message = str_replace("{MESSAGE_CONTENT}", $result, $body_message);
    	
    	// To send HTML mail, the Content-type header must be set
    	$headers  = 'MIME-Version: 1.0' . "\r\n";
    	$headers .= 'Content-type: text/html; charset=UTF-8' . "\r\n";
    	
    	// Additional headers
    	$headers .= 'From: '. $to . "\r\n";
    	
    	// Mail it
    	return mail($to, $subject, $body_message, $headers);
    }
    
	public function PrepareDomain($domain)
	{
	    $domain = str_replace( array("'", '"', '%', '!'), '', $domain);
	    $domain = strtolower($domain);
        
	    $host_info = parse_url($domain);
	    if ($host_info == NULL) return $domain;
	    $domain = $host_info['host'];
	    if ($domain[0] == "w" && $domain[1] == "w" && $domain[2] == "w" && $domain[3] == ".") $domain = str_replace("www.", "", $domain);
	    
	    return $domain;
    }
    
	public function DebugLog($txt, $clean_log_file = false)
	{
	    if ($txt == 'line') $txt = '-----------------------------------------------------------------------';
		if ($clean_log_file) $fp = fopen($this->tmp_dir.'debug_'.md5($this->access_key).'.log', 'w');
		else $fp = fopen($this->tmp_dir.'debug_'.md5($this->access_key).'.log', 'a');
		$a = date("Y-m-d H:i:s")." ".$txt."\n";
		fwrite($fp, $a);
		fclose($fp);
	}
	
	public function DebugLogFileList($file)
	{
		$fp = fopen($this->tmp_dir.'filelist_excluded_'.md5($this->access_key).'.txt', 'a');
		$a = $file."\n";
		fwrite($fp, $a);
		fclose($fp);
	}
    
	public function HugeFilesLog($txt)
	{
        $file = $this->tmp_dir.'report_excluded_files.php';
        if (!file_exists($file)) $txt = "<?php die(); ?>\n".$txt;
	    $fp = fopen($file, 'a');
		fwrite($fp, $txt."\n");
		fclose($fp);
	}
    
	public function UnwantedFilesLog($txt)
	{
        $file = $this->tmp_dir.'report_unwanted_files.php';
        if (!file_exists($file)) $txt = "<?php die(); ?>\n".$txt;
	    $fp = fopen($file, 'a');
		fwrite($fp, $txt."\n");
		fclose($fp);
	}
    
    
	public function NotReadableFilesLog($txt)
	{
        $file = $this->tmp_dir.'report_notreadable_files.php';
        if (!file_exists($file)) $txt = "<?php die(); ?>\n".$txt;
	    $fp = fopen($file, 'a');
		fwrite($fp, $txt."\n");
		fclose($fp);
	}
    
	public function ErrorLog($txt)
	{
	    $fp = fopen($this->tmp_dir.'antivirus_error.log', 'w');
		$a = date("Y-m-d H:i:s")." ".$txt."\n";
		fwrite($fp, $a);
		fclose($fp);
	}
	
	
	/**
	 * Checks PHP extensions / functions the scanner relies on and writes the
	 * result to the debug log. Missing optional pieces are reported; missing
	 * critical pieces are flagged as CRITICAL so they stand out in the log.
	 * This is diagnostics only - it never blocks the scan.
	 */
	public function CheckEnvironment()
	{
		self::DebugLog('--- Environment check (PHP '.PHP_VERSION.') ---');
		
		// name => array(type to test, value, critical?)
		$checks = array(
			array('label' => 'pcre',           'ok' => function_exists('preg_match'),            'critical' => true),
			array('label' => 'json',           'ok' => function_exists('json_encode'),           'critical' => true),
			array('label' => 'hash/md5',       'ok' => function_exists('md5'),                   'critical' => true),
			array('label' => 'curl',           'ok' => extension_loaded('curl'),                 'critical' => false),
			array('label' => 'allow_url_fopen','ok' => (bool)@ini_get('allow_url_fopen'),        'critical' => false),
			array('label' => 'mysqli',         'ok' => function_exists('mysqli_connect'),        'critical' => false),
			array('label' => 'zip(ZipArchive)','ok' => class_exists('ZipArchive'),               'critical' => false),
			array('label' => 'exec',           'ok' => function_exists('exec'),                  'critical' => false),
			array('label' => 'mbstring',       'ok' => function_exists('mb_detect_encoding'),    'critical' => false),
			array('label' => 'iconv',          'ok' => function_exists('iconv'),                 'critical' => false),
			array('label' => 'simplexml',      'ok' => function_exists('simplexml_load_file'),   'critical' => false),
			array('label' => 'openssl',        'ok' => function_exists('openssl_private_decrypt'),'critical' => false),
			array('label' => 'gd/getimagesize','ok' => function_exists('getimagesize'),          'critical' => false),
			array('label' => 'tokenizer',      'ok' => function_exists('token_get_all'),         'critical' => false),
		);
		
		// HTTP transport needs curl OR allow_url_fopen; flag if both are missing.
		$http_ok = extension_loaded('curl') || (bool)@ini_get('allow_url_fopen');
		// Packing needs ZipArchive OR exec(tar); flag if both are missing.
		$pack_ok = class_exists('ZipArchive') || function_exists('exec');
		
		foreach ($checks as $c)
		{
			if ($c['ok'])
			{
				self::DebugLog('ENV: '.$c['label'].' = OK');
			}
			else
			{
				$tag = $c['critical'] ? 'CRITICAL MISSING' : 'MISSING';
				self::DebugLog('ENV: '.$c['label'].' = '.$tag);
			}
		}
		
		if (!$http_ok)  self::DebugLog('ENV: HTTP transport = CRITICAL MISSING (no curl and allow_url_fopen is off) - server communication may fail');
		if (!$pack_ok)  self::DebugLog('ENV: file packing = CRITICAL MISSING (no ZipArchive and no exec) - cannot build the scan archive');
		
		self::DebugLog('--- Environment check end ---');
	}
	
	
	/**
	 * Returns true if the given file looks like PHP based on its content.
	 *
	 * Reads the file body (whole file up to SG_PHP_SNIFF_MAXSIZE, or only the
	 * first SG_PHP_SNIFF_READ bytes if that constant is non-zero) and looks for
	 * a PHP open tag anywhere in it. To keep false positives low we ONLY accept:
	 *     "<?php" followed by whitespace
	 *     "<?="   followed by whitespace
	 * The bare "<?" short tag is deliberately NOT matched, because it fires on
	 * "<?xml ..." (every SVG / XML / RSS file) and on random byte pairs in binary
	 * files. "Whitespace" means space, tab, CR or LF - not only a literal space -
	 * so the very common opening "<?php\n..." is still detected.
	 *
	 * All failures are swallowed (logged by the caller) so a single unreadable
	 * file can never abort the scan.
	 *
	 * @param  string $file      Absolute path to the file.
	 * @param  int    $file_size Known file size (bytes).
	 * @return bool
	 */
	public function IsPhpByContent($file, $file_size)
	{
		if ($file_size <= 0) return false;
		if ($file_size > SG_PHP_SNIFF_MAXSIZE) return false;
		
		$read_len = (SG_PHP_SNIFF_READ > 0) ? min(SG_PHP_SNIFF_READ, $file_size) : $file_size;
		
		$handle = @fopen($file, 'rb');
		if ($handle === false)
		{
			if (self::$debug) self::DebugLog('Sniff: cannot open '.$file);
			return false;
		}
		
		$contents = @fread($handle, $read_len);
		@fclose($handle);
		
		if ($contents === false || $contents === '') return false;
		
		// Only "<?php" or "<?=" immediately followed by whitespace (space/tab/CR/LF).
		if (preg_match('/<\?(?:php|=)[ \t\r\n]/', $contents)) return true;
		
		return false;
	}
}



class Siteguarding_Wordpress_Core_Check {
	
	private $core = array();
	private $plugins = array();
	private $themes = array();
	private $admins = array();
	private $options = array();
	private $database = '';
	private $sql_user = '';
	private $sql_pass = '';
	private $host = '';


	
	public function __construct($sql_settings) 
    {
        $this->database = $sql_settings['sql_database'];
		$this->sql_user = $sql_settings['sql_username'];
		$this->sql_pass = $sql_settings['sql_password'];
		$this->host = $sql_settings['sql_server'];
		$this->table_prefix = $sql_settings['prefix'];
		
		$this->db = SGAntiVirus_SQL_scanner::SafeConnect($this->host, $this->sql_user, $this->sql_pass, $this->database);
	}
	
	
	
	public function checkAllinWP() {
		return $this->checkCoreWP()
			->checkPlugins()
			->checkThemes()
			->checkAdmins()
			->checkOptions();
	}


	public function checkCoreWP() {
		
		$wp_version = '';
		$lastVersion = '';
		@require_once(SCAN_PATH . '/wp-includes/version.php');
		$lastVersion = @json_decode(@file_get_contents('https://api.wordpress.org/core/version-check/1.7/'))->offers[0]->version;

		$this->core['current_ver'] = $wp_version ? $wp_version : 'unknown';
		$this->core['latest_ver'] = $lastVersion ? $lastVersion : 'unknown';

		return $this;
	}
	
	private function _cleanup_header_comment( $str ) {
		return trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $str));
	}
	
	private function get_file_data( $file, $default_headers, $context = '' ) {
		
		$fp = fopen( $file, 'r' );
	 
		$file_data = fread( $fp, 8192 );
	 
		fclose( $fp );
	 
		$file_data = str_replace( "\r", "\n", $file_data );
	 
		if ( $context && $extra_headers = apply_filters( "extra_{$context}_headers", array() ) ) {
			$extra_headers = array_combine( $extra_headers, $extra_headers ); // keys equal values
			$all_headers = array_merge( $extra_headers, (array) $default_headers );
		} else {
			$all_headers = $default_headers;
		}
	 
		foreach ( $all_headers as $field => $regex ) {
			if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] )
				$all_headers[ $field ] = $this->_cleanup_header_comment( $match[1] );
			else
				$all_headers[ $field ] = '';
		}
 
		return $all_headers;
	}	

	public function checkPlugins() {

		$activeSlugs = array();
		$sql = "SELECT option_value FROM " . $this->table_prefix . "options WHERE option_name = 'active_plugins'";
		$result = mysqli_query($this->db, $sql);
		$row = mysqli_fetch_row($result);
		$activePlugins = unserialize($row[0]);
		foreach ($activePlugins as $plugin) {
			$tmpslug = explode("/", $plugin);
			$activeSlugs[] = $tmpslug[0];
		}
		
		
		$sql = "SELECT option_value FROM " . $this->table_prefix . "options WHERE option_name = '_site_transient_update_plugins'";
		$result = mysqli_query($this->db, $sql);
		$row = mysqli_fetch_row($result);
		$update_plugins = unserialize($row[0]);

		if ($update_plugins && !empty($update_plugins->response)) {
			foreach ($update_plugins->response as $plugin => $vals) {

				

				
				$pluginFile = SCAN_PATH . 'wp-content' . DIRSEP . 'plugins' . DIRSEP . $plugin;
				if (!file_exists($pluginFile)) { //Plugin has been removed since the update status was pulled
					continue;
				}
				
				$valsArray = (array) $vals;
				
				$slug = (isset($valsArray['slug']) ? $valsArray['slug'] : null);
				if ($slug === null) { //Plugin may have been removed from the repo or was never in it so guess
					if (preg_match('/^([^\/]+)\//', $pluginFile, $matches)) {
						$slug = $matches[1];
					}
					else if (preg_match('/^([^\/.]+)\.php$/', $pluginFile, $matches)) {
						$slug = $matches[1];
					}
				}

				$pluginData = $this->get_file_data($pluginFile, array('Name' => 'Plugin Name', 'Version' => 'Version'));

				$data['slug'] = (isset($valsArray['slug']) ? $valsArray['slug'] : null);
				$data['name'] = $pluginData['Name'];
				$data['active'] = (in_array($slug, $activeSlugs)) ? 1 : 0;
				$data['current_ver'] = $pluginData['Version'];;
				$data['latest_ver'] = (isset($valsArray['new_version']) ? $valsArray['new_version'] : 'Unknown');
				$data['file'] = $valsArray['plugin'];

				
				if ($slug !== null) {
					$this->plugins[$slug] = $data;
				}
			

			}
		}
		
		//We have to grab the slugs from the update response because no built-in function exists to return the true slug from the local files
		if ($update_plugins && !empty($update_plugins->no_update)) {
			foreach ($update_plugins->no_update as $plugin => $vals) {

				
				$pluginFile = SCAN_PATH . 'wp-content' . DIRSEP . 'plugins' . DIRSEP . $plugin;
				if (!file_exists($pluginFile)) { //Plugin has been removed since the update status was pulled
					continue;
				}
				
				
				$valsArray = (array) $vals;
				
				$slug = (isset($valsArray['slug']) ? $valsArray['slug'] : null);
				if ($slug === null) { //Plugin may have been removed from the repo or was never in it so guess
					if (preg_match('/^([^\/]+)\//', $pluginFile, $matches)) {
						$slug = $matches[1];
					}
					else if (preg_match('/^([^\/.]+)\.php$/', $pluginFile, $matches)) {
						$slug = $matches[1];
					}
				}
				
				$pluginData = $this->get_file_data($pluginFile, array('Name' => 'Plugin Name', 'Version' => 'Version'));
				
				$data['slug'] = (isset($valsArray['slug']) ? $valsArray['slug'] : null);
				$data['name'] = $pluginData['Name'];
				$data['active'] = (in_array($slug, $activeSlugs)) ? 1 : 0;
				$data['current_ver'] = $pluginData['Version'];;
				$data['latest_ver'] = (isset($valsArray['new_version']) ? $valsArray['new_version'] : 'Unknown');
				$data['file'] = $valsArray['plugin'];

				
				if (isset($valsArray['slug'])) {
					$this->plugins[$valsArray['slug']] = $data;
				}
				
			}	
		}


		
		return $this;
	}

	public function checkOptions()
    {
        $sql = "SELECT option_name, option_value FROM {$this->table_prefix}options WHERE option_name IN ('siteurl', 'home', 'admin_email')";
        
        $result = mysqli_query($this->db, $sql);
		while ($row = mysqli_fetch_assoc($result)) 
        {
			$this->options[ $row['option_name'] ] = $row['option_value'];
		}
		return $this;
    }

    
	public function checkAdmins() {
        $sql =  "SELECT a.user_login, a.user_email FROM {$this->table_prefix}users a INNER JOIN {$this->table_prefix}usermeta b ON ( a.ID = b.user_id ) WHERE b.meta_value LIKE '%\"Administrator\"%'";

		$result = mysqli_query($this->db, $sql);
		while ($row = mysqli_fetch_assoc($result)) {
			$this->admins[] = array('username' => $row['user_login'], 'email' => $row['user_email']);
		}
		return $this;
	}

	public function checkThemes() {
		
		$this->themes = array();

		$sql = "SELECT option_value FROM " . $this->table_prefix . "options WHERE option_name = '_site_transient_update_themes'";
		$result = mysqli_query($this->db, $sql);
		$row = mysqli_fetch_row($result);
		$update_themes = unserialize($row[0]);		
		
		
		
		$sql = "SELECT option_value FROM " . $this->table_prefix . "options WHERE option_name = 'template'";
		$result = mysqli_query($this->db, $sql);
		$row = mysqli_fetch_row($result);
		$current = $row[0];

		if ($update_themes) {

			foreach ($update_themes->checked as $theme => $currentVersion) {
				
				$this->themes[] = array(

					'name'       => $theme,
					'active'       => ($theme == $current) ? 1 : 0,
					'current_ver'    => $currentVersion,
					'latest_ver' => (isset($update_themes->response[$theme]) ? $update_themes->response[$theme]['new_version'] : $currentVersion),
				);

			}
		}

		return $this;
		
	}




	public function getCoreCheckResult() {
		return $this->core;
	}


	public function getPluginsCheckResult() {
		return $this->plugins;
	}
	


	public function getThemesCheckResult() {
		return $this->themes;
	}	


	public function getAdminsCheckResult() {
		return $this->admins;
	}
    
	public function getOptionsResult() {
		return $this->options;
	}	


	public function getFullResultsToArray() {
		$this->checkAllinWP();
		
		$result['core'] = $this->getCoreCheckResult();
		$result['plugins'] = $this->getPluginsCheckResult();
		$result['themes'] = $this->getThemesCheckResult();
		$result['admins'] = $this->getAdminsCheckResult();
        
		$result['options'] = $this->getOptionsResult();
		
		return $result;
	}
}

class Siteguarding_Joomla_Core_Check {

    private $core = array();
    private $admins = array();
    private $table_prefix = '';


    public function __construct($sql_settings)
    {
        $this->table_prefix = $sql_settings['prefix'];
        $this->db = SGAntiVirus_SQL_scanner::SafeConnect($sql_settings['sql_server'], $sql_settings['sql_username'], $sql_settings['sql_password'], $sql_settings['sql_database']);
    }



    public function checkAllinJoomla() 
	{
        return $this->checkCoreJoomla()
            ->checkAdmins();
    }


    public function checkCoreJoomla() 
	{
        $xml_file = SCAN_PATH . 'language'.DIRECTORY_SEPARATOR.'en-GB'.DIRECTORY_SEPARATOR.'en-GB.xml';
        if (file_exists($xml_file))
        {
            $xml = simplexml_load_file($xml_file);
            $joomla_version = (string) $xml->version;
        }
        
        $lastVersion = @json_decode(@file_get_contents('https://downloads.joomla.org/api/v1/latest/cms'))->branches[3]->version;

        $this->core['current_ver'] = $joomla_version ? $joomla_version : 'unknown';
        $this->core['latest_ver'] = $lastVersion ? $lastVersion : 'unknown';

        return $this;
    }

    public function checkAdmins()
	{
        $sql =  "SELECT a.id, a.username, a.email, b.group_id FROM {$this->table_prefix}users a INNER JOIN {$this->table_prefix}user_usergroup_map b ON ( a.ID = b.user_id ) WHERE b.group_id IN (7,8)";

        $result = mysqli_query($this->db, $sql);
        while ($row = mysqli_fetch_assoc($result)) {
            $this->admins[] = array('username' => $row['username'], 'email' => $row['email']);
        }
        return $this;
    }


    public function getCoreCheckResult() 
	{
        return $this->core;
    }



    public function getAdminsCheckResult() 
	{
        return $this->admins;
    }


    public function getFullResultsToArray() 
	{
        $this->checkAllinJoomla();

        $result['core'] = $this->getCoreCheckResult();
        $result['admins'] = $this->getAdminsCheckResult();

        return $result;
    }
}



/*
Dont delete this line 95D5C9AB68C2                                      |
*/